Import Upstream version 2.4.7
This commit is contained in:
commit
4c2bbe068f
|
@ -0,0 +1,10 @@
|
|||
cache/
|
||||
.sconsign.dblite
|
||||
config.h
|
||||
config_debug.h
|
||||
libffado.pc
|
||||
version.h
|
||||
*.pyc
|
||||
*.o
|
||||
*.os
|
||||
*.so
|
|
@ -0,0 +1,9 @@
|
|||
Daniel Wagner <wagi@monom.org>
|
||||
Pieter Palmers <pieter.palmers@ffado.org>
|
||||
Jonathan Woithe <jwoithe@just42.net>
|
||||
Arnold Krille <arnold@arnoldarts.de>
|
||||
Adrian Knoth <adi@drcomp.erfurt.thur.de>
|
||||
Philippe Carriere <la-page-web-of-phil.contact@orange.fr>
|
||||
Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
||||
Stefan Richter <stefanr@s5r6.in-berlin.de>
|
||||
Jano Svitok <jan.svitok@gmail.com>
|
|
@ -0,0 +1,2 @@
|
|||
REMARK: Please use the SVN commit messages as replacement for ChangeLog
|
||||
|
|
@ -0,0 +1,339 @@
|
|||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
@ -0,0 +1,340 @@
|
|||
FFADO v2.4
|
||||
==========
|
||||
|
||||
The FFADO project aims to provide a free driver implementation for FireWire
|
||||
(IEEE1394, iLink) based audio interfaces. The focus of the project are on
|
||||
audio/music production rather than consumer audio. This means that although
|
||||
we intend to supported all features at some point, consumer features are
|
||||
considered less important. The most obvious example of a consumer feature
|
||||
is AC3/DTS pass-through support, which is unsupported at the moment.
|
||||
|
||||
This package provides the libffado shared library that provides a unified
|
||||
programming interface to configure and use all supported devices. Currently
|
||||
this library is used by the "firewire" backends of the jack audio connection
|
||||
kit sound server (jackaudio.org). This backend provides audio and midi
|
||||
support, and is available both in jackd and its multiprocessor variant
|
||||
jackdmp. At present there is no support for ALSA or pulseaudio, although
|
||||
jack bridging solutions may help in some situations.
|
||||
|
||||
Access to the device internal configuration (the internal mixer and device
|
||||
settings) is exposed using the ffado-dbus-server daemon. This daemon
|
||||
exposes the configurable parameters of all detected devices through DBUS.
|
||||
The ffado-mixer application in support/mixer/ presents a GUI to control these
|
||||
parameters.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* 24-bit audio input/output (number of channels only limited by interface
|
||||
hardware)
|
||||
* supports for all sample rates a device supports
|
||||
* MIDI input/output (unlimited number of channels)
|
||||
* Support for S/PDIF and ADAT/SMUX I/O
|
||||
* Internal mixer and device control support for all officially supported
|
||||
devices (NOTE: no support for internal DSP)
|
||||
* Support for device aggregation (limited to devices on the same bus)
|
||||
|
||||
Device Support
|
||||
--------------
|
||||
|
||||
The "officially supported" label is only given to devices that fulfil the
|
||||
following:
|
||||
* at least one of the developers has the device
|
||||
* the vendor provides development support (access to information)
|
||||
* the device works
|
||||
|
||||
The devices which are officially supported are:
|
||||
* ESI Quatafire 610
|
||||
* Terratec Producer Phase 88
|
||||
* Focusrite Saffire (original/white)
|
||||
* Focusrite Saffire Pro10
|
||||
* Focusrite Saffire Pro26
|
||||
* Focusrite Saffire Pro14, Pro40
|
||||
* ECHO AudioFire2, AudioFire4, AudioFire8, AudioFire12
|
||||
* Mackie Onyx Mixer FireWire expansion
|
||||
* RME Fireface 400, RME Fireface 800
|
||||
|
||||
The FFADO driver is written to provide generic support for all devices it
|
||||
might be able to handle. This means that most devices based on the BridgeCo
|
||||
BeBoB, the ECHO FireWorks platform or the TC Electronics DICE platform will
|
||||
work, at least to a certain extent. For some devices specific functions
|
||||
have been added to augment the generic framework and provide enhanced
|
||||
support, usually in the area of device and mixer control.
|
||||
|
||||
FFADO includes device-specific functionality for following devices. The
|
||||
code has been developed based on feedback received from users, and it has
|
||||
been reported to work by users. Note that FFADO may not support all device
|
||||
functions.
|
||||
* Presonus Firebox and Inspire1394
|
||||
* Presonus FireStudio Tube, FireStudio Project
|
||||
* M-Audio Ozonic, FireWire Solo
|
||||
* M-Audio Profire 2626, 610
|
||||
* M-Audio Audiophile and 410 (latest firmware and startup workaround needed,
|
||||
see http://sourceforge.net/p/ffado/mailman/message/30807938)
|
||||
* M-Audio 1814 and ProjectMix (mixer only, audio streaming not supported. and
|
||||
FireWire 1814 needs startup workaround above)
|
||||
* Focusrite Saffire Pro24
|
||||
* Focusrite Saffire Pro24 DSP (audio streaming only, DSP control not available)
|
||||
* Yamaha GO44 and GO46
|
||||
|
||||
Devices that have been reported to (partially) work with the generic support:
|
||||
* Presonus FirePod / FP10
|
||||
* Alesis io14
|
||||
* TC Konnekt 8, Konnekt 24D, Konnekt Live
|
||||
|
||||
As a result of a significant reverse-engineering effort a selection of
|
||||
devices from MOTU are supported. The developers had no support from the
|
||||
device vendor and this of course limits the extent to which problems can be
|
||||
solved. You have been warned. Please do not buy devices for which support
|
||||
is based upon reverse engineering, nor from vendors who are hostile towards
|
||||
Linux like MOTU. Value the support that some vendors provide and buy their
|
||||
stuff. Check ffado.org for details. It can't be said enough: currently it
|
||||
is extremely unwise to buy a MOTU device if you intend to use Linux.
|
||||
MOTU devices reported to work with FFADO are:
|
||||
* MOTU Traveler
|
||||
* MOTU 828mkII, MOTU Ultralite, MOTU 896HD, MOTU 8pre, MOTU 4pre
|
||||
* Audio only: MOTU Ultralite mk3, MOTU Traveler mk3, MOTU 896mk3, MOTU 828mk3
|
||||
* Audio only, FireWire interface only: MOTU Ultralite mk3 hybrid
|
||||
|
||||
"Audio only" means that FFADO can be used to stream audio to and from the
|
||||
device, control sample rate and clock source. Control of the mixer and DSP
|
||||
functions is not presently supported. It is planned but no ETA is available
|
||||
at this stage.
|
||||
|
||||
Devices for which work is in progress. These are not yet usable:
|
||||
* RME UFX and UCX FireWire devices
|
||||
|
||||
Usupported devices:
|
||||
* Presonus FireStation
|
||||
* Other TC Konnekt devices
|
||||
* Other Alesis devices
|
||||
* Metric Halo devices
|
||||
|
||||
We constantly try to persuade vendors to help us extend our device support.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
FFADO uses the scons build system, which must be available on the system
|
||||
when building FFADO. It is not a runtime dependency. Scons 2 is currently
|
||||
used to build FFADO. Work continues on making FFADO's scons scripts
|
||||
compatible with both scons 2 and 3. Testing and bug reports when using
|
||||
scons 3 are welcomed.
|
||||
|
||||
To build libffado you need several libraries. For all libraries a
|
||||
version is provided which is a "known good" version. The first few
|
||||
libraries it seems it is not necessary that the version must
|
||||
match. The chances that it works also with an older versions are good:
|
||||
|
||||
libxml++2 (>= 2.6.13)
|
||||
|
||||
These libraries here should be at least the version listed:
|
||||
|
||||
libraw1394 (>= 2.0.7), https://ieee1394.wiki.kernel.org/
|
||||
libiec61883 (>= 1.1.0), https://ieee1394.wiki.kernel.org/
|
||||
dbus-1 (>= 1.0), http://dbus.freedesktop.org
|
||||
dbus-c++ (>= 0), http://sourceforge.net/apps/mediawiki/dbus-cplusplus/
|
||||
libconfig (>= 0), http://www.hyperrealm.com/libconfig/
|
||||
|
||||
Currently only the jackd audio server is supported:
|
||||
jackd (>= 0.109.12), http://jackaudio.org
|
||||
|
||||
While jack1 0.109.12 will work, jack1 >= 0.122.0 or jack2 >= 1.9.9 are
|
||||
recommended if support for jack's setbufsize functionality is desired.
|
||||
|
||||
Optionally, but recommended is that you install qjackctl:
|
||||
|
||||
qjackctl (>= 0.2.20.10), http://sourceforge.net/projects/qjackctl
|
||||
|
||||
To build the optional ffado device mixer control utility you also require:
|
||||
|
||||
Qt >= 4.0, http://qt-project.org/
|
||||
SIP >= 4.7.0, http://www.riverbankcomputing.co.uk/software/sip/intro
|
||||
PyQt (note below), http://www.riverbankcomputing.co.uk/software/pyqt/intro
|
||||
dbus-python >= 0.82.0, http://dbus.freedesktop.org/releases/dbus-python/
|
||||
|
||||
The version of PyQt must be chosen to exactly match the version of Qt in use.
|
||||
For Qt 4.x use PyQt 4.x.
|
||||
|
||||
SIP is only required to compile PyQt. If using a binary package of PyQt
|
||||
SIP should not be needed.
|
||||
|
||||
Packages for building on Debian/Ubuntu distributions are installed with:
|
||||
|
||||
$ sudo apt-get install build-essential subversion scons libxml++2.6-dev \
|
||||
libiec61883-dev libdbus-1-dev libdbus-c++-bin \
|
||||
libdbus-c++-dev libconfig++-dev pyqt5-dev-tools \
|
||||
python3-dbus.mainloop.pyqt5 pyqt5-sip
|
||||
|
||||
How to build
|
||||
------------
|
||||
|
||||
If you want to build the release version you can simply do following:
|
||||
|
||||
$ scons
|
||||
$ scons install [as root or via sudo]
|
||||
|
||||
If you want some debug information (because something seems not
|
||||
to work correctly) you can try to do:
|
||||
|
||||
$ scons DEBUG=yes
|
||||
$ scons install [as root or via sudo]
|
||||
|
||||
Cleaning a build is done with:
|
||||
|
||||
$ scons -c -Q
|
||||
|
||||
More extended instructions can be found here:
|
||||
http://subversion.ffado.org/wiki/InstallingFfadoFromSource
|
||||
|
||||
NOTE: In order to build jackd with ffado support, you have
|
||||
to install libffado before you build jackd. The backend to use in jackd is
|
||||
"firewire".
|
||||
|
||||
NOTE: the beta versions are distributed with debugging enabled by default.
|
||||
|
||||
DISTRIBUTION PACKAGERS NOTE: Please do not enable support for devices
|
||||
if it is not on by default. If device support for a specific device
|
||||
is not turned on by default by the developers, it means that it is not
|
||||
ready yet. Most of the time it is placeholder code for future devices.
|
||||
|
||||
Running jackd
|
||||
-------------
|
||||
|
||||
The easiest way to run this is using qjackctl. There are only minor
|
||||
differences with the other backends, however you should change some
|
||||
of the default values:
|
||||
- It is recommended to change the "periods/buffer" field to 3, especially
|
||||
if you use low period sizes (=< 128)
|
||||
- It is recommended to raise the RT priority to 70.
|
||||
|
||||
In order to get it running from the command line, you need to provide some
|
||||
arguments to jackd.
|
||||
|
||||
Run
|
||||
|
||||
$ jackd -d firewire --help
|
||||
|
||||
to see the backend options. You can easily figure out how to set them using
|
||||
the remarks given above (for qjackctl).
|
||||
|
||||
For the other aspects of jackd usage, consult the jackd documentation.
|
||||
|
||||
Here is a sample session (without realtime support enabled):
|
||||
|
||||
$ jackd -d firewire
|
||||
no message buffer overruns
|
||||
jackd 0.111.0
|
||||
Copyright 2001-2005 Paul Davis and others.
|
||||
jackd comes with ABSOLUTELY NO WARRANTY
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; see the file COPYING for details
|
||||
|
||||
JACK compiled with System V SHM support.
|
||||
loading driver ..
|
||||
3106528665: (ffado.cpp)[ 99] ffado_streaming_init: libffado 1.999.20 built Apr 26 2008 20:26:32
|
||||
libiec61883 warning: Established connection on channel 0.
|
||||
You may need to manually set the channel on the receiving node.
|
||||
libiec61883 warning: Established connection on channel 1.
|
||||
You may need to manually set the channel on the transmitting node.
|
||||
|
||||
(Note: you can safely ignore the libiec61883 warnings, they are normal.)
|
||||
|
||||
An important remark is that for good performance, one should always run jack
|
||||
with the -R flag to enable realtime scheduling for critical threads:
|
||||
$ jackd -R -d firewire
|
||||
In most cases this is now the default.
|
||||
|
||||
For best results across most hardware it is necessary to use a kernel
|
||||
configured with the "Low latency desktop" option (CONFIG_PREEMPT) enabled.
|
||||
Most distributions provide this as an option, often called "low latency".
|
||||
In general it is no longer necessary to use an RT-patched kernel.
|
||||
|
||||
Ffado-mixer look and feel
|
||||
-------------------------
|
||||
|
||||
The look and feel of ffado-mixer can be changed via QT themes. When a dark
|
||||
mode is required, install a suitable QT theme. Some users have found the
|
||||
dark theme from UKUI to work well with ffado-mixer (often available in
|
||||
distributions through the qt5-ukui-platformtheme package).
|
||||
|
||||
In case of problems
|
||||
-------------------
|
||||
|
||||
First of all, check whether your problem is a known issue, and whether
|
||||
it is a FFADO problem. Use your chosen web search engine for this.
|
||||
|
||||
Many distributor kernels now include the alternative ALSA audio streaming
|
||||
drivers for selected FireWire audio interfaces (snd-bebob, snd-dice, etc).
|
||||
These are developed independently of FFADO. If these kernel modules are
|
||||
loaded then FFADO's streaming engine cannot be used: using jackd's
|
||||
"firewire" driver will fail because the kernel drivers have ownership of the
|
||||
interface. To continue to use FFADO's streaming system, the applicable
|
||||
snd-* module must be unloaded from the kernel and prevented from loading on
|
||||
boot. Use "rmmod" to remove the module from the running system, and
|
||||
blacklist the relevant snd-* module in a file under /lib/modprobe.d/ (or
|
||||
your distribution's equivalent).
|
||||
|
||||
When seeking support from the developers keep in mind that none of the FFADO
|
||||
developers are paid to work on FFADO or to support FFADO users. Answering
|
||||
the same question multiple times reduces the amount of time they have to
|
||||
work on the code. Before contacting the developers please see if your query
|
||||
or problem has been seen before. The following places are helpful:
|
||||
* http://www.ffado.org/
|
||||
* http://subversion.ffado.org/
|
||||
* your chosen search engine
|
||||
(the terms "ffado-devel" and "ffado-user" work well)
|
||||
|
||||
If you have tried to find a solution to your problem but couldn't or are
|
||||
confused, don't hesitate to ask for help. The preferred way is by signing
|
||||
up to the mailing list as described on http://www.ffado.org/?q=contact.
|
||||
|
||||
Writing a bug report
|
||||
--------------------
|
||||
|
||||
Note that the more effort you put in your bug report, the more effort we
|
||||
will put into helping you.
|
||||
|
||||
Make sure you have compiled a DEBUG=yes version of
|
||||
libffado. If not there is no way we can trace the problem.
|
||||
|
||||
When reporting a problem, please run jackd with the --verbose option,
|
||||
and add the -v6 option to the firewire backend:
|
||||
$ jackd --verbose [...] -d firewire -v6 [...]
|
||||
|
||||
( [...] = other options )
|
||||
|
||||
This will generate an increadible amount of debug output that should
|
||||
contain what we need to track down the problem. If you have troubles
|
||||
saving the output, try redirecting it to a file:
|
||||
|
||||
$ jackd --verbose -d firewire -v6 2> ffado-jack.log
|
||||
|
||||
this will create a ffado.log file containing the output. Use CTRL-C
|
||||
to exit jack if necessary.
|
||||
|
||||
The distribution contains a tool to gather some information about your
|
||||
system. When FFADO is installed on the system it can be run directly:
|
||||
|
||||
$ ffado-diag > ffado-diag.log
|
||||
|
||||
It is also possible to run it from the source tree:
|
||||
|
||||
$ cd support/tools
|
||||
$ python ffado-diag.py > ffado-diag.log
|
||||
|
||||
It will check your system for basic problems and gather some information
|
||||
regarding your hardware configuration. This will allow us to diagnose
|
||||
your problem faster.
|
||||
|
||||
Once the logs have been created you can create a support ticket at
|
||||
http://subversion.ffado.org/newticket
|
||||
|
||||
Be sure to include the following information:
|
||||
* the log file(s) (zipped/tar.gz'ed and attached)
|
||||
* the device you're trying to use
|
||||
* a description of what went wrong and how to reproduce it. You
|
||||
preferably try to figure out a sequence of steps that can reliably
|
||||
reproduce the issue on your system. A one-time failure is very difficult
|
||||
to diagnose and/or fix.
|
||||
* the distribution and its version
|
|
@ -0,0 +1,992 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2007, 2008, 2010 Arnold Krille
|
||||
# Copyright (C) 2007, 2008 Pieter Palmers
|
||||
# Copyright (C) 2008, 2012 Jonathan Woithe
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from __future__ import print_function
|
||||
|
||||
FFADO_API_VERSION = "9"
|
||||
FFADO_VERSION="2.4.7"
|
||||
|
||||
from subprocess import Popen, PIPE, check_output
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from string import Template
|
||||
import distutils.sysconfig
|
||||
|
||||
if not os.path.isdir( "cache" ):
|
||||
os.makedirs( "cache" )
|
||||
|
||||
opts = Variables( "cache/options.cache" )
|
||||
|
||||
opts.AddVariables(
|
||||
BoolVariable( "DEBUG", """\
|
||||
Build with \"-g -Wall\" rather than \"-O2\", and include extra debugging
|
||||
checks in the code.""", True ),
|
||||
BoolVariable( "DEBUG_MESSAGES", "Enable support for debug messages", True ),
|
||||
BoolVariable( "PROFILE", "Build with symbols, warnings and other profiling info", False ),
|
||||
PathVariable( "PREFIX", "The prefix where ffado will be installed to.", "/usr/local", PathVariable.PathAccept ),
|
||||
PathVariable( "BINDIR", "Overwrite the directory where apps are installed to.", "$PREFIX/bin", PathVariable.PathAccept ),
|
||||
PathVariable( "LIBDIR", "Overwrite the directory where libs are installed to.", "$PREFIX/lib", PathVariable.PathAccept ),
|
||||
PathVariable( "INCLUDEDIR", "Overwrite the directory where headers are installed to.", "$PREFIX/include", PathVariable.PathAccept ),
|
||||
PathVariable( "SHAREDIR", "Overwrite the directory where misc shared files are installed to.", "$PREFIX/share/libffado", PathVariable.PathAccept ),
|
||||
PathVariable( "LIBDATADIR", "Location for architecture-dependent data.", "$LIBDIR/libffado", PathVariable.PathAccept ),
|
||||
PathVariable( "MANDIR", "Overwrite the directory where manpages are installed", "$PREFIX/man", PathVariable.PathAccept ),
|
||||
PathVariable( "PYPKGDIR", "The directory where the python modules get installed.",
|
||||
distutils.sysconfig.get_python_lib( prefix="$PREFIX" ), PathVariable.PathAccept ),
|
||||
PathVariable( "UDEVDIR", "Overwrite the directory where udev rules are installed to.", "/lib/udev/rules.d/", PathVariable.PathAccept ),
|
||||
BoolVariable( "ENABLE_BEBOB", "Enable/Disable support for the BeBoB platform.", True ),
|
||||
BoolVariable( "ENABLE_FIREWORKS", "Enable/Disable support for the ECHO Audio FireWorks platform.", True ),
|
||||
BoolVariable( "ENABLE_OXFORD", "Enable/Disable support for the Oxford Semiconductor FW platform.", True ),
|
||||
BoolVariable( "ENABLE_MOTU", "Enable/Disable support for the MOTU platform.", True ),
|
||||
BoolVariable( "ENABLE_DICE", "Enable/Disable support for the TCAT DICE platform.", True ),
|
||||
BoolVariable( "ENABLE_METRIC_HALO", "Enable/Disable support for the Metric Halo platform.", False ),
|
||||
BoolVariable( "ENABLE_RME", "Enable/Disable support for the RME platform.", True ),
|
||||
BoolVariable( "ENABLE_DIGIDESIGN", "Enable/Disable support for Digidesign interfaces.", False ),
|
||||
BoolVariable( "ENABLE_BOUNCE", "Enable/Disable the BOUNCE device.", False ),
|
||||
BoolVariable( "ENABLE_GENERICAVC", """\
|
||||
Enable/Disable the the generic avc part (mainly used by apple).
|
||||
Note that disabling this option might be overwritten by other devices needing
|
||||
this code.""", False ),
|
||||
BoolVariable( "ENABLE_ALL", "Enable/Disable support for all devices.", False ),
|
||||
BoolVariable( "SERIALIZE_USE_EXPAT", "Use libexpat for XML serialization.", False ),
|
||||
EnumVariable( "BUILD_DOC", "Build API documentation", 'none', allowed_values=('all', 'user', 'none'), ignorecase=2),
|
||||
EnumVariable( "BUILD_MIXER", "Build the ffado-mixer", 'auto', allowed_values=('auto', 'true', 'false'), ignorecase=2),
|
||||
BoolVariable( "BUILD_TESTS", """\
|
||||
Build the tests in their directory. As some contain quite some functionality,
|
||||
this is on by default.
|
||||
If you just want to use ffado with jack without the tools, you can disable this.\
|
||||
""", True ),
|
||||
BoolVariable( "BUILD_STATIC_TOOLS", "Build a statically linked version of the FFADO tools.", False ),
|
||||
EnumVariable('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'powerpc64', 'none' ), ignorecase=2),
|
||||
BoolVariable( "ENABLE_OPTIMIZATIONS", "Enable optimizations and the use of processor specific extentions (MMX/SSE/...).", False ),
|
||||
BoolVariable( "DETECT_USERSPACE_ENV", "Try to detect the user space environment and add necessary 32/64 bit machine flags.", True ),
|
||||
BoolVariable( "PEDANTIC", "Enable -Werror and more pedantic options during compile.", False ),
|
||||
BoolVariable( "CUSTOM_ENV", "Respect CC, CXX, CFLAGS, CXXFLAGS and LDFLAGS.\nOnly meant for distributors and gentoo-users who want to over-optimize their build.\n Using this is not supported by the ffado-devs!", False ),
|
||||
( "COMPILE_FLAGS", "Deprecated (use CFLAGS and CXXFLAGS with CUSTOM_ENV=True instead). Add additional flags to the environment.\nOnly meant for distributors and gentoo-users who want to over-optimize their build.\n Using this is not supported by the ffado-devs!" ),
|
||||
EnumVariable( "ENABLE_SETBUFFERSIZE_API_VER", "Report API version at runtime which includes support for dynamic buffer resizing (requires recent jack).", 'auto', allowed_values=('auto', 'true', 'false', 'force'), ignorecase=2),
|
||||
("PYTHON_INTERPRETER", "Python interpreter to be used by FFADO installation.", "/usr/bin/python"),
|
||||
|
||||
)
|
||||
|
||||
## Load the builders in config
|
||||
buildenv=os.environ
|
||||
|
||||
env = Environment( tools=['default','scanreplace','pyuic','pyuic4','pyuic5','dbus','doxygen','pkgconfig'], toolpath=['admin'], ENV = buildenv, options=opts )
|
||||
|
||||
custom_flags = False
|
||||
|
||||
if 'COMPILE_FLAGS' in env and len(env['COMPILE_FLAGS']) > 0:
|
||||
print("The COMPILE_FLAGS option is deprecated. Use CFLAGS and CXXFLAGS with CUSTOM_ENV=True instead")
|
||||
custom_flags = True
|
||||
env.MergeFlags(env['COMPILE_FLAGS'])
|
||||
|
||||
if env['CUSTOM_ENV']:
|
||||
custom_flags = True
|
||||
|
||||
# Honour the user choice of compiler (if any).
|
||||
if 'CC' in os.environ and len(os.environ['CC']) > 0:
|
||||
env['CC'] = os.environ['CC']
|
||||
if 'CXX' in os.environ and len(os.environ['CXX']) > 0:
|
||||
env['CXX'] = os.environ['CXX']
|
||||
|
||||
# Honour the user supplied flags (if any), but notify the user that this is not supported.
|
||||
if 'CFLAGS' in os.environ and len(os.environ['CFLAGS']) > 0:
|
||||
env.Append(CFLAGS = str(os.environ['CFLAGS'].replace('\"', '')))
|
||||
if 'CXXFLAGS' in os.environ and len(os.environ['CXXFLAGS']) > 0:
|
||||
env.Append(CXXFLAGS = str(os.environ['CXXFLAGS'].replace('\"', '')))
|
||||
if 'LDFLAGS' in os.environ and len(os.environ['LDFLAGS']) > 0:
|
||||
env.Append(LINKFLAGS = str(os.environ['LDFLAGS'].replace('\"', '')))
|
||||
|
||||
if custom_flags:
|
||||
print('''
|
||||
* Usage of additional flags is not supported by the ffado-devs.
|
||||
* Use at own risk!
|
||||
*
|
||||
* Flags in use:
|
||||
* CC = %s
|
||||
* CXX = %s
|
||||
* CFLAGS = %s
|
||||
* CXXFLAGS = %s
|
||||
* LDFLAGS = %s
|
||||
''' % (env['CC'], env['CXX'], env['CFLAGS'], env['CXXFLAGS'], env['LINKFLAGS']))
|
||||
|
||||
Help( """
|
||||
For building ffado you can set different options as listed below. You have to
|
||||
specify them only once, scons will save the last value you used and re-use
|
||||
that.
|
||||
To really undo your settings and return to the factory defaults, remove the
|
||||
"cache"-folder and the file ".sconsign.dblite" from this directory.
|
||||
For example with: "rm -Rf .sconsign.dblite cache"
|
||||
|
||||
Note that this is a development version! Don't complain if its not working!
|
||||
See www.ffado.org for stable releases.
|
||||
""" )
|
||||
Help( opts.GenerateHelpText( env ) )
|
||||
|
||||
# make sure the necessary dirs exist
|
||||
if not os.path.isdir( "cache" ):
|
||||
os.makedirs( "cache" )
|
||||
if not os.path.isdir( 'cache/objects' ):
|
||||
os.makedirs( 'cache/objects' )
|
||||
|
||||
CacheDir( 'cache/objects' )
|
||||
|
||||
opts.Save( 'cache/options.cache', env )
|
||||
|
||||
def ConfigGuess( context ):
|
||||
context.Message( "Trying to find the system triple: " )
|
||||
ret = check_output(("/bin/sh", "admin/config.guess")).rstrip()
|
||||
context.Result( ret )
|
||||
return ret.decode()
|
||||
|
||||
def CheckForApp( context, app ):
|
||||
context.Message( "Checking whether '" + app + "' executes " )
|
||||
ret = context.TryAction( app )
|
||||
context.Result( ret[0] )
|
||||
return ret[0]
|
||||
|
||||
def CheckForPyModule( context, module ):
|
||||
context.Message( "Checking for the python module '" + module + "' " )
|
||||
ret = context.TryAction( "$PYTHON_INTERPRETER $SOURCE", "import %s" % module, ".py" )
|
||||
context.Result( ret[0] )
|
||||
return ret[0]
|
||||
|
||||
def CompilerCheck( context ):
|
||||
context.Message( "Checking for a working C-compiler " )
|
||||
ret = context.TryRun( """
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf( "Hello World!" );
|
||||
return 0;
|
||||
}""", '.c' )[0]
|
||||
context.Result( ret )
|
||||
if ret == 0:
|
||||
return False;
|
||||
context.Message( "Checking for a working C++-compiler " )
|
||||
ret = context.TryRun( """
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello World!" << std::endl;
|
||||
return 0;
|
||||
}""", ".cpp" )[0]
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
def CheckPKG(context, name):
|
||||
context.Message( 'Checking for %s... ' % name )
|
||||
ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
tests = {
|
||||
"ConfigGuess" : ConfigGuess,
|
||||
"CheckForApp" : CheckForApp,
|
||||
"CheckForPyModule": CheckForPyModule,
|
||||
"CompilerCheck" : CompilerCheck,
|
||||
"CheckPKG" : CheckPKG,
|
||||
}
|
||||
tests.update( env['PKGCONFIG_TESTS'] )
|
||||
tests.update( env['PYUIC_TESTS'] )
|
||||
tests.update( env['PYUIC4_TESTS'] )
|
||||
|
||||
conf = Configure( env,
|
||||
custom_tests = tests,
|
||||
conf_dir = "cache/",
|
||||
log_file = 'cache/config.log' )
|
||||
|
||||
version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)')
|
||||
|
||||
def CheckJackdVer():
|
||||
print('Checking jackd version...', end='')
|
||||
popen = Popen(("which", 'jackd'), stdout=PIPE, stderr=PIPE)
|
||||
stdout, stderr = popen.communicate()
|
||||
assert popen.returncode in (0, 1), "which returned a unexpected status"
|
||||
if popen.returncode == 1:
|
||||
print("not installed")
|
||||
return None
|
||||
jackd = stdout.decode ().rstrip ()
|
||||
ret = check_output ((jackd, '--version')).decode() .rstrip ()
|
||||
ret = ret.split ('\n') [-1]; # Last line.
|
||||
ret = ret.split () [2]; # Third field.
|
||||
if not version_re.match (ret):
|
||||
print("failed to parse version")
|
||||
return None
|
||||
print (ret)
|
||||
|
||||
# Trim off any "rc" (release candidate) components from the end of the
|
||||
# version string
|
||||
ret = ret.split ('rc')[0]
|
||||
ret = ret.split ('.')
|
||||
ret = map (int, ret)
|
||||
return tuple (ret)
|
||||
|
||||
if env['SERIALIZE_USE_EXPAT']:
|
||||
env['SERIALIZE_USE_EXPAT']=1
|
||||
else:
|
||||
env['SERIALIZE_USE_EXPAT']=0
|
||||
|
||||
if env['ENABLE_BOUNCE'] or env['ENABLE_ALL']:
|
||||
env['REQUIRE_LIBAVC']=1
|
||||
else:
|
||||
env['REQUIRE_LIBAVC']=0
|
||||
|
||||
if not env.GetOption('clean'):
|
||||
#
|
||||
# Check for working gcc and g++ compilers and their environment.
|
||||
#
|
||||
if not conf.CompilerCheck():
|
||||
print("\nIt seems as if your system isn't even able to compile any C-/C++-programs. Probably you don't have gcc and g++ installed. Compiling a package from source without a working compiler is very hard to do, please install the needed packages.\nHint: on *ubuntu you need both gcc- and g++-packages installed, easiest solution is to install build-essential which depends on gcc and g++.")
|
||||
Exit( 1 )
|
||||
|
||||
# Check for pkg-config before using pkg-config to check for other dependencies.
|
||||
if not conf.CheckForPKGConfig():
|
||||
print("\nThe program 'pkg-config' could not be found.\nEither you have to install the corresponding package first or make sure that PATH points to the right directions.")
|
||||
Exit( 1 )
|
||||
|
||||
#
|
||||
# The following checks are for headers and libs and packages we need.
|
||||
#
|
||||
allpresent = 1;
|
||||
# for cache-serialization.
|
||||
if env['SERIALIZE_USE_EXPAT']:
|
||||
allpresent &= conf.CheckHeader( "expat.h" )
|
||||
allpresent &= conf.CheckLib( 'expat', 'XML_ExpatVersion', '#include <expat.h>' )
|
||||
|
||||
pkgs = {
|
||||
'libraw1394' : '2.0.5',
|
||||
'libiec61883' : '1.1.0',
|
||||
'libconfig++' : '0'
|
||||
}
|
||||
|
||||
if env['REQUIRE_LIBAVC']:
|
||||
pkgs['libavc1394'] = '0.5.3'
|
||||
|
||||
if not env['SERIALIZE_USE_EXPAT']:
|
||||
if conf.CheckPKG('libxml++-3.0'):
|
||||
pkgs['libxml++-3.0'] = '3.0.0'
|
||||
if not('libxml++-3.0' in pkgs):
|
||||
pkgs['libxml++-2.6'] = '2.13.0'
|
||||
|
||||
# Provide a way for users to compile newer libffado which will work
|
||||
# against older jack installations which will not accept the new API
|
||||
# version reported at runtime.
|
||||
have_jack = conf.CheckPKG('jack')
|
||||
if have_jack:
|
||||
good_jack1 = conf.CheckPKG('jack < 1.9.0') and conf.CheckPKG('jack >= 0.121.4')
|
||||
good_jack2 = conf.CheckPKG('jack >= 1.9.9')
|
||||
else:
|
||||
jackd_ver = CheckJackdVer()
|
||||
if jackd_ver:
|
||||
# If jackd is unknown to pkg-config but is never-the-less
|
||||
# runnable, use the version number reported by it. This means
|
||||
# users don't have to have jack development files present on
|
||||
# their system for this to work.
|
||||
have_jack = jackd_ver >= (0, 0, 0)
|
||||
good_jack1 = jackd_ver < (1, 9, 0) and jackd_ver >= (0, 121, 4)
|
||||
good_jack2 = jackd_ver >= (1, 9, 9)
|
||||
|
||||
if env['ENABLE_SETBUFFERSIZE_API_VER'] == 'auto':
|
||||
if not(have_jack):
|
||||
print("""
|
||||
No Jack Audio Connection Kit (JACK) installed: assuming a FFADO
|
||||
setbuffersize-compatible version will be used.
|
||||
""")
|
||||
elif not(good_jack1 or good_jack2):
|
||||
FFADO_API_VERSION="8"
|
||||
print("""
|
||||
Installed Jack Audio Connection Kit (JACK) jack does not support FFADO
|
||||
setbuffersize API: will report earlier API version at runtime. Consider
|
||||
upgrading to jack1 >=0.122.0 or jack2 >=1.9.9 at some point, and then
|
||||
recompile ffado to gain access to this added feature.
|
||||
""")
|
||||
else:
|
||||
print("Installed Jack Audio Connection Kit (JACK) supports FFADO setbuffersize API")
|
||||
elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'true':
|
||||
if (have_jack and not(good_jack1) and not(good_jack2)):
|
||||
print("""
|
||||
SetBufferSize API version is enabled but no suitable version of Jack Audio
|
||||
Connection Kit (JACK) has been found. The resulting FFADO would cause your
|
||||
jackd to abort with "incompatible FFADO version". Please upgrade to
|
||||
jack1 >=0.122.0 or jack2 >=1.9.9, or set ENABLE_SETBUFFERSIZE_API_VER to "auto"
|
||||
or "false".
|
||||
""")
|
||||
# Although it's not strictly an error, in almost every case that
|
||||
# this occurs the user will want to know about it and fix the
|
||||
# problem, so we exit so they're guaranteed of seeing the above
|
||||
# message.
|
||||
Exit( 1 )
|
||||
else:
|
||||
print("Will report SetBufferSize API version at runtime")
|
||||
elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'force':
|
||||
print("Will report SetBufferSize API version at runtime")
|
||||
else:
|
||||
FFADO_API_VERSION="8"
|
||||
print("Will not report SetBufferSize API version at runtime")
|
||||
|
||||
for pkg in pkgs:
|
||||
name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
|
||||
env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
|
||||
#print('%s_FLAGS' % name2)
|
||||
if env['%s_FLAGS'%name2] == 0:
|
||||
allpresent &= 0
|
||||
|
||||
if not allpresent:
|
||||
print("""
|
||||
(At least) One of the dependencies is missing. I can't go on without it, please
|
||||
install the needed packages for each of the lines saying "no".
|
||||
(Remember to also install the *-devel packages!)
|
||||
|
||||
And remember to remove the cache with "rm -Rf .sconsign.dblite cache" so the
|
||||
results above get rechecked.
|
||||
""")
|
||||
Exit( 1 )
|
||||
|
||||
# libxml++-2.6 requires a c++11 compiler as of version 2.39.1. The
|
||||
# gnu++11 standard seems to work both with these later libxml++ versions
|
||||
# and ffado itself, although a significant number of warnings are
|
||||
# produced. Add the necessary option to CXXFLAGS if required.
|
||||
if conf.CheckPKG('libxml++-2.6 >= 2.39.1'):
|
||||
env.Append(CXXFLAGS = '-std=gnu++11')
|
||||
if conf.CheckPKG('libxml++-3.0 >= 3.0.0'):
|
||||
env.Append(CXXFLAGS = '-std=gnu++11')
|
||||
|
||||
# Check for C99 lrint() and lrintf() functions used to convert from
|
||||
# float to integer more efficiently via float_cast.h. If not
|
||||
# present the standard slower methods will be used instead. This
|
||||
# might not be the best way of testing for these but it's the only
|
||||
# way which seems to work properly. CheckFunc() fails due to
|
||||
# argument count problems.
|
||||
if 'CFLAGS' in env:
|
||||
oldcf = env['CFLAGS']
|
||||
else:
|
||||
oldcf = ""
|
||||
env.Append(CFLAGS = '-std=c99')
|
||||
if conf.CheckLibWithHeader( "m", "math.h", "c", "lrint(3.2);" ):
|
||||
HAVE_LRINT = 1
|
||||
else:
|
||||
HAVE_LRINT = 0
|
||||
if conf.CheckLibWithHeader( "m", "math.h", "c", "lrintf(3.2);" ):
|
||||
HAVE_LRINTF = 1
|
||||
else:
|
||||
HAVE_LRINTF = 0
|
||||
env['HAVE_LRINT'] = HAVE_LRINT;
|
||||
env['HAVE_LRINTF'] = HAVE_LRINTF;
|
||||
env.Replace(CFLAGS=oldcf)
|
||||
|
||||
#
|
||||
# Optional checks follow:
|
||||
#
|
||||
|
||||
# PyQT checks
|
||||
if env['BUILD_MIXER'] != 'false':
|
||||
if ( conf.CheckForApp( 'which pyuic4' ) \
|
||||
and conf.CheckForPyModule( 'PyQt4' ) \
|
||||
and conf.CheckForPyModule( 'dbus.mainloop.qt' )) \
|
||||
or ( conf.CheckForApp( 'which pyuic5' ) \
|
||||
and conf.CheckForPyModule( 'PyQt5' ) \
|
||||
and conf.CheckForPyModule( 'dbus.mainloop.pyqt5' )):
|
||||
env['BUILD_MIXER'] = 'true'
|
||||
elif not env.GetOption('clean'):
|
||||
if env['BUILD_MIXER'] == 'auto':
|
||||
env['BUILD_MIXER'] = 'false'
|
||||
print("""
|
||||
The prerequisites ('pyuic4'/'pyuic5' and the python-modules 'dbus' and
|
||||
'PyQt4'/'PyQt5', the packages could be named like dbus-python and PyQt) to
|
||||
build the mixer were not found. Therefore the qt mixer will not be installed.""")
|
||||
else: # env['BUILD_MIXER'] == 'true'
|
||||
print("""
|
||||
The prerequisites ('pyuic4'/'pyuic5' and the python-modules 'dbus' and
|
||||
'PyQt4'/'PyQt5', the packages could be named like dbus-python and PyQt) to
|
||||
build the mixer were not found, but BUILD_MIXER was requested.""")
|
||||
Exit( 1 )
|
||||
|
||||
env['XDG_TOOLS'] = False
|
||||
if env['BUILD_MIXER'] == 'true':
|
||||
if conf.CheckForApp( 'xdg-desktop-menu --help' ) and conf.CheckForApp( 'xdg-icon-resource --help' ):
|
||||
env['XDG_TOOLS'] = True
|
||||
else:
|
||||
print("""
|
||||
I couldn't find the 'xdg-desktop-menu' and 'xdg-icon-resource' programs. These
|
||||
are needed to add the fancy entry for the mixer to your menu, but you can still
|
||||
start it by executing "ffado-mixer".""")
|
||||
|
||||
#
|
||||
# Optional pkg-config
|
||||
#
|
||||
pkgs = {
|
||||
'alsa': '0',
|
||||
'dbus-1': '1.0',
|
||||
'dbus-c++-1' : '0',
|
||||
}
|
||||
for pkg in pkgs:
|
||||
name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
|
||||
env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
|
||||
|
||||
if not env['DBUS1_FLAGS'] or not env['DBUSC1_FLAGS'] or not conf.CheckForApp('which dbusxx-xml2cpp'):
|
||||
env['DBUS1_FLAGS'] = b""
|
||||
env['DBUSC1_FLAGS'] = b""
|
||||
print("""
|
||||
One of the dbus-headers, the dbus-c++-headers and/or the application
|
||||
'dbusxx-xml2cpp' where not found. The dbus-server for ffado will therefore not
|
||||
be built.
|
||||
""")
|
||||
else:
|
||||
# Get the directory where dbus stores the service-files
|
||||
env['dbus_service_dir'] = conf.GetPKGVariable( 'dbus-1', 'session_bus_services_dir' ).strip()
|
||||
# this is required to indicate that the DBUS version we use has support
|
||||
# for platform dependent threading init functions
|
||||
# this is true for DBUS >= 0.96 or so. Since we require >= 1.0 it is
|
||||
# always true
|
||||
env['DBUS1_FLAGS'] += b" -DDBUS_HAS_THREADS_INIT_DEFAULT"
|
||||
|
||||
# The controlserver-glue.h file generated by dbusxx-xml2cpp generates
|
||||
# a large number of instances where call.reader()'s return value is
|
||||
# stored (in ri) but not used. This generates a compiler warning which
|
||||
# we can do nothing about. Therefore when compiling dbus-related
|
||||
# code, suppress the "set but not used" warning.
|
||||
env['DBUS1_FLAGS'] += b" -Wno-unused-but-set-variable"
|
||||
|
||||
config_guess = conf.ConfigGuess()
|
||||
|
||||
conf.Finish()
|
||||
|
||||
if env['DEBUG']:
|
||||
print("Doing a debug build")
|
||||
env.MergeFlags( "-Wall -g -DDEBUG" )
|
||||
env['DEBUG_MESSAGES'] = True
|
||||
elif not custom_flags:
|
||||
# Only merge -O2 to flags if the user has not specified custom flags.
|
||||
env.MergeFlags( "-O2" )
|
||||
|
||||
if env['DEBUG_MESSAGES']:
|
||||
env.MergeFlags( "-DDEBUG_MESSAGES" )
|
||||
|
||||
if env['PROFILE']:
|
||||
print("Doing a PROFILE build")
|
||||
env.MergeFlags( "-Wall -g" )
|
||||
|
||||
if env['PEDANTIC']:
|
||||
env.MergeFlags( "-Werror" )
|
||||
|
||||
|
||||
if env['ENABLE_ALL']:
|
||||
env['ENABLE_BEBOB'] = True
|
||||
env['ENABLE_FIREWORKS'] = True
|
||||
env['ENABLE_OXFORD'] = True
|
||||
env['ENABLE_MOTU'] = True
|
||||
env['ENABLE_DICE'] = True
|
||||
env['ENABLE_METRIC_HALO'] = True
|
||||
env['ENABLE_RME'] = True
|
||||
env['ENABLE_DIGIDESIGN'] = True
|
||||
env['ENABLE_BOUNCE'] = True
|
||||
|
||||
|
||||
env['BUILD_STATIC_LIB'] = False
|
||||
if env['BUILD_STATIC_TOOLS']:
|
||||
print("Building static versions of the tools...")
|
||||
env['BUILD_STATIC_LIB'] = True
|
||||
|
||||
env['build_base']="#/"
|
||||
|
||||
#
|
||||
# Get the DESTDIR (if wanted) from the commandline
|
||||
#
|
||||
env.destdir = ARGUMENTS.get( 'DESTDIR', "" )
|
||||
|
||||
#
|
||||
# Uppercase variables are for usage in code, lowercase versions for usage in
|
||||
# scons-files for installing.
|
||||
#
|
||||
env['BINDIR'] = Template( env['BINDIR'] ).safe_substitute( env )
|
||||
env['LIBDIR'] = Template( env['LIBDIR'] ).safe_substitute( env )
|
||||
env['INCLUDEDIR'] = Template( env['INCLUDEDIR'] ).safe_substitute( env )
|
||||
env['SHAREDIR'] = Template( env['SHAREDIR'] ).safe_substitute( env )
|
||||
env['LIBDATADIR'] = Template( env['LIBDATADIR'] ).safe_substitute( env )
|
||||
env['UDEVDIR'] = Template( env['UDEVDIR'] ).safe_substitute( env )
|
||||
env['PYTHON_INTERPRETER'] = Template( env['PYTHON_INTERPRETER'] ).safe_substitute( env )
|
||||
env['prefix'] = Template( env.destdir + env['PREFIX'] ).safe_substitute( env )
|
||||
env['bindir'] = Template( env.destdir + env['BINDIR'] ).safe_substitute( env )
|
||||
env['libdir'] = Template( env.destdir + env['LIBDIR'] ).safe_substitute( env )
|
||||
env['includedir'] = Template( env.destdir + env['INCLUDEDIR'] ).safe_substitute( env )
|
||||
env['sharedir'] = Template( env.destdir + env['SHAREDIR'] ).safe_substitute( env )
|
||||
env['libdatadir'] = Template( env.destdir + env['LIBDATADIR'] ).safe_substitute( env )
|
||||
env['mandir'] = Template( env.destdir + env['MANDIR'] ).safe_substitute( env )
|
||||
env['pypkgdir'] = Template( env.destdir + env['PYPKGDIR'] ).safe_substitute( env )
|
||||
env['udevdir'] = Template( env.destdir + env['UDEVDIR'] ).safe_substitute( env )
|
||||
env['PYPKGDIR'] = Template( env['PYPKGDIR'] ).safe_substitute( env )
|
||||
env['metainfodir'] = Template( env.destdir + "/usr/share/metainfo" ).safe_substitute( env )
|
||||
|
||||
env.Command( target=env['sharedir'], source="", action=Mkdir( env['sharedir'] ) )
|
||||
|
||||
env.Alias( "install", env['libdir'] )
|
||||
env.Alias( "install", env['includedir'] )
|
||||
env.Alias( "install", env['sharedir'] )
|
||||
env.Alias( "install", env['libdatadir'] )
|
||||
env.Alias( "install", env['bindir'] )
|
||||
env.Alias( "install", env['mandir'] )
|
||||
if env['BUILD_MIXER'] == 'true':
|
||||
env.Alias( "install", env['pypkgdir'] )
|
||||
env.Alias( "install", env['metainfodir'] )
|
||||
|
||||
#
|
||||
# shamelessly copied from the Ardour scons file
|
||||
#
|
||||
|
||||
opt_flags = []
|
||||
env['USE_SSE'] = 0
|
||||
|
||||
# guess at the platform, used to define compiler flags
|
||||
|
||||
config_cpu = 0
|
||||
config_arch = 1
|
||||
config_kernel = 2
|
||||
config_os = 3
|
||||
config = config_guess.split ("-")
|
||||
|
||||
needs_fPIC = False
|
||||
|
||||
#=== Begin Revised CXXFLAGS =========================================
|
||||
def cpuinfo_kv():
|
||||
"""generator which reads lines from Linux /proc/cpuinfo and splits them
|
||||
into key:value tokens and yields (key, value) tuple.
|
||||
"""
|
||||
with open('/proc/cpuinfo', 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
k,v = line.split(':', 1)
|
||||
yield (k.strip(), v.strip())
|
||||
|
||||
class CpuInfo (object):
|
||||
"""Collects information about the CPU, mainly from /proc/cpuinfo
|
||||
"""
|
||||
def __init__(self):
|
||||
self.sysname, self.hostname, self.release, self.version, self.machine = os.uname()
|
||||
# general CPU architecture
|
||||
self.is_x86 = self.machine in ('i686', 'x86_64') or \
|
||||
re.match("i[3-5]86", self.machine) or False
|
||||
self.is_powerpc = self.machine in ('ppc64', 'ppc', 'powerpc', 'powerpc64', 'ppc64le')
|
||||
#!!! probably not comprehensive
|
||||
self.is_mips = self.machine == 'mips'
|
||||
#!!! not a comprehensive list. uname -m on one android phone reports 'armv71'
|
||||
# I have no other arm devices I can check
|
||||
self.is_arm = self.machine in ('armv71', )
|
||||
|
||||
self.cpu_count = 0
|
||||
if self.is_x86:
|
||||
self.cpu_info_x86()
|
||||
elif self.is_powerpc:
|
||||
self.cpu_info_ppc()
|
||||
elif self.is_mips:
|
||||
self.cpu_info_mips()
|
||||
|
||||
# 64-bit (x86_64/AMD64/Intel64)
|
||||
# Long Mode (x86-64: amd64, also known as Intel 64, i.e. 64-bit capable)
|
||||
self.is_64bit = (self.is_x86 and 'lm' in self.x86_flags) or \
|
||||
(self.is_powerpc and \
|
||||
('970' in self.ppc_type or 'power8' in self.ppc_type.lower()))
|
||||
|
||||
# Hardware virtualization capable: vmx (Intel), svm (AMD, Hygon)
|
||||
self.has_hwvirt = self.is_x86 and (
|
||||
((self.is_amd or self.is_hygon) and
|
||||
'svm' in self.x86_flags) or
|
||||
(self.is_intel and 'vmx' in self.x86_flags))
|
||||
|
||||
# Physical Address Extensions (support for more than 4GB of RAM)
|
||||
self.has_pae = self.is_x86 and 'pae' in self.x86_flags
|
||||
|
||||
|
||||
def cpu_info_x86(self):
|
||||
"parse /proc/cpuinfo for x86 kernels"
|
||||
for k,v in cpuinfo_kv():
|
||||
if k == 'processor':
|
||||
self.cpu_count += 1
|
||||
if self.cpu_count > 1:
|
||||
# assume all CPUs are identical features, no need to
|
||||
# parse all of them
|
||||
continue
|
||||
elif k == 'vendor_id': # AuthenticAMD, HygonGenuine, GenuineIntel
|
||||
self.vendor_id = v
|
||||
self.is_amd = v == 'AuthenticAMD'
|
||||
self.is_hygon = v == 'HygonGenuine'
|
||||
self.is_intel = v == 'GenuineIntel'
|
||||
elif k == 'flags':
|
||||
self.x86_flags = v.split()
|
||||
elif k == 'model name':
|
||||
self.model_name = v
|
||||
elif k == 'cpu family':
|
||||
self.cpu_family = v
|
||||
elif k == 'model':
|
||||
self.model = v
|
||||
|
||||
def cpu_info_ppc(self):
|
||||
"parse /proc/cpuinfo for PowerPC kernels"
|
||||
# http://en.wikipedia.org/wiki/List_of_PowerPC_processors
|
||||
# PowerPC 7xx family
|
||||
# PowerPC 740 and 750, 233-366 MHz
|
||||
# 745/755, 300–466 MHz
|
||||
|
||||
# PowerPC G4 series
|
||||
# 7400/7410 350 - 550 MHz, uses AltiVec, a SIMD extension of the original PPC specs
|
||||
# 7450 micro-architecture family up to 1.5 GHz and 256 kB on-chip L2 cache and improved Altivec
|
||||
# 7447/7457 micro-architecture family up to 1.8 GHz with 512 kB on-chip L2 cache
|
||||
# 7448 micro-architecture family (1.5 GHz) in 90 nm with 1MB L2 cache and slightly
|
||||
# improved AltiVec (out of order instructions).
|
||||
# 8640/8641/8640D/8641D with one or two e600 (Formerly known as G4) cores, 1MB L2 cache
|
||||
|
||||
# PowerPC G5 series
|
||||
# 970 (2003), 64-bit, derived from POWER4, enhanced with VMX, 512 kB L2 cache, 1.4 – 2 GHz
|
||||
# 970FX (2004), manufactured at 90 nm, 1.8 - 2.7 GHz
|
||||
# 970GX (2006), manufactured at 90 nm, 1MB L2 cache/core, 1.2 - 2.5 GHz
|
||||
# 970MP (2005), dual core, 1 MB L2 cache/core, 1.6 - 2.5 GHz
|
||||
for k,v in cpuinfo_kv():
|
||||
if k == 'processor':
|
||||
self.cpu_count += 1
|
||||
elif k == 'cpu':
|
||||
self.is_altivec_supported = 'altivec' in v
|
||||
if ',' in v:
|
||||
ppc_type, x = v.split(',')
|
||||
else:
|
||||
ppc_type = v
|
||||
self.ppc_type = ppc_type.strip()
|
||||
# older kernels might not have a 'processor' line
|
||||
if self.cpu_count == 0:
|
||||
self.cpu_count += 1
|
||||
|
||||
|
||||
def cpu_info_mips(self):
|
||||
"parse /proc/cpuinfo for MIPS kernels"
|
||||
for k,v in cpuinfo_kv():
|
||||
if k == 'processor':
|
||||
self.cpu_count += 1
|
||||
elif k == 'cpu model':
|
||||
self.mips_cpu_model = v
|
||||
|
||||
|
||||
def is_userspace_32bit(cpuinfo):
|
||||
"""Even if `uname -m` reports a 64-bit architecture, userspace could still
|
||||
be 32-bit, such as Debian on powerpc64. This function tries to figure out
|
||||
if userspace is 32-bit, i.e. we might need to pass '-m32' or '-m64' to gcc.
|
||||
"""
|
||||
if not cpuinfo.is_64bit:
|
||||
return True
|
||||
# note that having a 64-bit CPU means nothing for these purposes. You could
|
||||
# run a completely 32-bit system on a 64-bit capable CPU.
|
||||
answer = None
|
||||
|
||||
# If setting DIST_TARGET to i686 on a 64-bit CPU to facilitate
|
||||
# compilation of a multilib environment, force 32-bit.
|
||||
if env['DIST_TARGET'] == 'i686':
|
||||
return True
|
||||
|
||||
# Debian ppc64 returns machine 'ppc64', but userspace might be 32-bit
|
||||
# We'll make an educated guess by examining a known executable
|
||||
exe = '/bin/mount'
|
||||
if os.path.isfile(exe):
|
||||
#print('Found %s' % exe)
|
||||
if os.path.islink(exe):
|
||||
real_exe = os.path.join(os.path.dirname(exe), os.readlink(exe))
|
||||
#print('%s is a symlink to %s' % (exe, real_exe))
|
||||
else:
|
||||
real_exe = exe
|
||||
# presumably if a person is running this script, they should have
|
||||
# a gcc toolchain installed...
|
||||
x = check_output(('objdump', '-Wi', real_exe)).decode()
|
||||
# should emit a line that looks like this:
|
||||
# /bin/mount: file format elf32-i386
|
||||
# or like this:
|
||||
# /bin/mount: file format elf64-x86-64
|
||||
# or like this:
|
||||
# /bin/mount: file format elf32-powerpc
|
||||
for line in x.split('\n'):
|
||||
line = line.strip()
|
||||
if line.startswith(real_exe):
|
||||
x, fmt = line.rsplit(None, 1)
|
||||
answer = 'elf32' in fmt
|
||||
break
|
||||
else:
|
||||
print('!!! Not found %s' % exe)
|
||||
return answer
|
||||
|
||||
|
||||
def cc_flags_x86(cpuinfo, enable_optimizations):
|
||||
"""add certain gcc -m flags based on CPU features
|
||||
"""
|
||||
# See http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/i386-and-x86_002d64-Options.html
|
||||
cc_opts = []
|
||||
if cpuinfo.machine == 'i586':
|
||||
cc_opts.append('-march=i586')
|
||||
elif cpuinfo.machine == 'i686':
|
||||
cc_opts.append('-march=i686')
|
||||
|
||||
if 'mmx' in cpuinfo.x86_flags:
|
||||
cc_opts.append('-mmmx')
|
||||
|
||||
# map from proc/cpuinfo flags to gcc options
|
||||
opt_flags = [
|
||||
('sse', ('-mfpmath=sse', '-msse')),
|
||||
('sse2', '-msse2'),
|
||||
('ssse3', '-mssse3'),
|
||||
('sse4', '-msse4'),
|
||||
('sse4_1', '-msse4.1'),
|
||||
('sse4_2', '-msse4.2'),
|
||||
('sse4a', '-msse4a'),
|
||||
('3dnow', '-m3dnow'),
|
||||
]
|
||||
if enable_optimizations:
|
||||
for flag, gccopt in opt_flags:
|
||||
if flag in cpuinfo.x86_flags:
|
||||
if isinstance(gccopt, (tuple, list)):
|
||||
cc_opts.extend(gccopt)
|
||||
else:
|
||||
cc_opts.append(gccopt)
|
||||
return cc_opts
|
||||
|
||||
|
||||
def cc_flags_powerpc(cpuinfo, enable_optimizations):
|
||||
"""add certain gcc -m flags based on CPU model
|
||||
"""
|
||||
cc_opts = []
|
||||
if cpuinfo.is_altivec_supported:
|
||||
cc_opts.append ('-maltivec')
|
||||
cc_opts.append ('-mabi=altivec')
|
||||
|
||||
if re.match('74[0145][0578]A?', cpuinfo.ppc_type) is not None:
|
||||
cc_opts.append ('-mcpu=7400')
|
||||
cc_opts.append ('-mtune=7400')
|
||||
elif re.match('750', cpuinfo.ppc_type) is not None:
|
||||
cc_opts.append ('-mcpu=750')
|
||||
cc_opts.append ('-mtune=750')
|
||||
elif re.match('PPC970', cpuinfo.ppc_type) is not None:
|
||||
cc_opts.append ('-mcpu=970')
|
||||
cc_opts.append ('-mtune=970')
|
||||
elif re.match('Cell Broadband Engine', cpuinfo.ppc_type) is not None:
|
||||
cc_opts.append('-mcpu=cell')
|
||||
cc_opts.append('-mtune=cell')
|
||||
return cc_opts
|
||||
#=== End Revised CXXFLAGS =========================================
|
||||
|
||||
# Autodetect
|
||||
if env['DIST_TARGET'] == 'auto':
|
||||
if re.search ("x86_64", config[config_cpu]) is not None:
|
||||
env['DIST_TARGET'] = 'x86_64'
|
||||
elif re.search("i[0-5]86", config[config_cpu]) is not None:
|
||||
env['DIST_TARGET'] = 'i386'
|
||||
elif re.search("i686", config[config_cpu]) is not None:
|
||||
env['DIST_TARGET'] = 'i686'
|
||||
elif re.search("powerpc64", config[config_cpu]) is not None:
|
||||
env['DIST_TARGET'] = 'powerpc64'
|
||||
elif re.search("powerpc", config[config_cpu]) is not None:
|
||||
env['DIST_TARGET'] = 'powerpc'
|
||||
else:
|
||||
env['DIST_TARGET'] = config[config_cpu]
|
||||
print("Detected DIST_TARGET = " + env['DIST_TARGET'])
|
||||
|
||||
#=== Begin Revised CXXFLAGS =========================================
|
||||
# comment on DIST_TARGET up top implies it can be used for cross-compiling
|
||||
# but that's not true because even if it is not 'auto' the original
|
||||
# script still reads /proc/cpuinfo to determine gcc arch flags.
|
||||
# This script does the same as the original. Needs to be fixed someday.
|
||||
cpuinfo = CpuInfo()
|
||||
if cpuinfo.is_x86:
|
||||
opt_flags.extend(cc_flags_x86(cpuinfo, env['ENABLE_OPTIMIZATIONS']))
|
||||
if cpuinfo.is_powerpc:
|
||||
opt_flags.extend(cc_flags_powerpc(cpuinfo, env['ENABLE_OPTIMIZATIONS']))
|
||||
if '-msse' in opt_flags:
|
||||
env['USE_SSE'] = 1
|
||||
if '-msse2' in opt_flags:
|
||||
env['USE_SSE2'] = 1
|
||||
|
||||
if env['DETECT_USERSPACE_ENV']:
|
||||
m32 = is_userspace_32bit(cpuinfo)
|
||||
print('User space is %s' % (m32 and '32-bit' or '64-bit'))
|
||||
if cpuinfo.is_powerpc:
|
||||
if m32:
|
||||
print("Doing a 32-bit PowerPC build for %s CPU" % cpuinfo.ppc_type)
|
||||
machineflags = { 'CXXFLAGS' : ['-m32'] }
|
||||
else:
|
||||
print("Doing a 64-bit PowerPC build for %s CPU" % cpuinfo.ppc_type)
|
||||
machineflags = { 'CXXFLAGS' : ['-m64'] }
|
||||
env.MergeFlags( machineflags )
|
||||
elif cpuinfo.is_x86:
|
||||
if m32:
|
||||
print("Doing a 32-bit %s build for %s" % (cpuinfo.machine, cpuinfo.model_name))
|
||||
if cpuinfo.machine == 'x86_64':
|
||||
machineflags = { 'CXXFLAGS' : ['-mx32'] }
|
||||
else:
|
||||
machineflags = { 'CXXFLAGS' : ['-m32'] }
|
||||
else:
|
||||
print("Doing a 64-bit %s build for %s" % (cpuinfo.machine, cpuinfo.model_name))
|
||||
machineflags = { 'CXXFLAGS' : ['-m64'] }
|
||||
needs_fPIC = True
|
||||
env.MergeFlags( machineflags )
|
||||
#=== End Revised CXXFLAGS =========================================
|
||||
|
||||
|
||||
if needs_fPIC or ( 'COMPILE_FLAGS' in env and '-fPIC' in env['COMPILE_FLAGS'] ):
|
||||
env.MergeFlags( "-fPIC" )
|
||||
|
||||
# end of processor-specific section
|
||||
if env['ENABLE_OPTIMIZATIONS']:
|
||||
opt_flags.extend (["-fomit-frame-pointer","-ffast-math","-funroll-loops"])
|
||||
env.MergeFlags( opt_flags )
|
||||
print("Doing an optimized build...")
|
||||
|
||||
try:
|
||||
env['REVISION'] = check_output(('svnversion', '.',)).decode().rstrip()
|
||||
except:
|
||||
env['REVISION'] = ''
|
||||
|
||||
# This may be as simple as '89' or as complex as '4123:4184M'.
|
||||
# We'll just use the last bit.
|
||||
env['REVISION'] = env['REVISION'].split(':')[-1]
|
||||
|
||||
# Assume an unversioned directory indicates a release.
|
||||
if env['REVISION'].startswith ('Unversioned'):
|
||||
env['REVISION'] = ''
|
||||
|
||||
# try to circumvent localized versions
|
||||
if env['REVISION'].startswith ('export'):
|
||||
env['REVISION'] = ''
|
||||
|
||||
# avoid the 1.999.41- type of version for exported versions
|
||||
if env['REVISION'] != '':
|
||||
env['REVISIONSTRING'] = '-' + env['REVISION']
|
||||
else:
|
||||
env['REVISIONSTRING'] = ''
|
||||
|
||||
env['FFADO_API_VERSION'] = FFADO_API_VERSION
|
||||
|
||||
env['PACKAGE'] = "libffado"
|
||||
env['VERSION'] = FFADO_VERSION
|
||||
env['LIBVERSION'] = "1.0.0"
|
||||
|
||||
env['CONFIGDIR'] = "~/.ffado"
|
||||
env['CACHEDIR'] = "~/.ffado"
|
||||
|
||||
env['USER_CONFIG_FILE'] = env['CONFIGDIR'] + "/configuration"
|
||||
env['SYSTEM_CONFIG_FILE'] = env['SHAREDIR'] + "/configuration"
|
||||
|
||||
env['REGISTRATION_URL'] = "http://ffado.org/deviceregistration/register.php?action=register"
|
||||
|
||||
#
|
||||
# To have the top_srcdir as the doxygen-script is used from auto*
|
||||
#
|
||||
env['top_srcdir'] = env.Dir( "." ).abspath
|
||||
|
||||
#
|
||||
# Start building
|
||||
#
|
||||
env.ScanReplace( "config.h.in" )
|
||||
env.ScanReplace( "config_debug.h.in" )
|
||||
env.ScanReplace( "version.h.in" )
|
||||
|
||||
# ensure that the config.h is updated
|
||||
env.Depends( "config.h", "SConstruct" )
|
||||
env.Depends( "config.h", 'cache/options.cache' )
|
||||
|
||||
# update version.h whenever the version or SVN revision changes
|
||||
env.Depends( "version.h", env.Value(env['REVISION']))
|
||||
env.Depends( "version.h", env.Value(env['VERSION']))
|
||||
|
||||
env.Depends( "libffado.pc", "SConstruct" )
|
||||
pkgconfig = env.ScanReplace( "libffado.pc.in" )
|
||||
env.Install( env['libdir'] + '/pkgconfig', pkgconfig )
|
||||
|
||||
env.Install( env['sharedir'], 'configuration' )
|
||||
|
||||
subdirs=['src','libffado','support','doc']
|
||||
if env['BUILD_TESTS']:
|
||||
subdirs.append('tests')
|
||||
|
||||
env.SConscript( dirs=subdirs, exports="env" )
|
||||
|
||||
if 'debian' in COMMAND_LINE_TARGETS:
|
||||
env.SConscript("deb/SConscript", exports="env")
|
||||
|
||||
# By default only src is built but all is cleaned
|
||||
if not env.GetOption('clean'):
|
||||
Default( 'src' )
|
||||
Default( 'support' )
|
||||
if env['BUILD_TESTS']:
|
||||
Default( 'tests' )
|
||||
if env['BUILD_DOC'] != 'none':
|
||||
Default( 'doc' )
|
||||
|
||||
env.Install( env['metainfodir'], "support/xdg/ffado-mixer.appdata.xml" )
|
||||
|
||||
#
|
||||
# Deal with the DESTDIR vs. xdg-tools conflict (which is basicely that the
|
||||
# xdg-tools can't deal with DESTDIR, so the packagers have to deal with this
|
||||
# their own :-/
|
||||
#
|
||||
if len(env.destdir) > 0:
|
||||
if not len( ARGUMENTS.get( "WILL_DEAL_WITH_XDG_MYSELF", "" ) ) > 0:
|
||||
print("""
|
||||
WARNING!
|
||||
You are using the (packagers) option DESTDIR to install this package to a
|
||||
different place than the real prefix. As the xdg-tools can't cope with
|
||||
that, the .desktop-files are not installed by this build, you have to
|
||||
deal with them your own.
|
||||
(And you have to look into the SConstruct to learn how to disable this
|
||||
message.)
|
||||
""")
|
||||
else:
|
||||
|
||||
def CleanAction( action ):
|
||||
if env.GetOption( "clean" ):
|
||||
env.Execute( action )
|
||||
|
||||
if env['BUILD_MIXER'] == 'true' and env['XDG_TOOLS']:
|
||||
if not env.GetOption("clean"):
|
||||
action = "install"
|
||||
else:
|
||||
action = "uninstall"
|
||||
mixerdesktopaction = env.Action( "-xdg-desktop-menu %s support/xdg/ffado.org-ffadomixer.desktop" % action )
|
||||
mixericonaction = env.Action( "-xdg-icon-resource %s --size 64 --novendor --context apps support/xdg/hi64-apps-ffado.png ffado" % action )
|
||||
env.Command( "__xdgstuff1", None, mixerdesktopaction )
|
||||
env.Command( "__xdgstuff2", None, mixericonaction )
|
||||
env.Alias( "install", ["__xdgstuff1", "__xdgstuff2" ] )
|
||||
CleanAction( mixerdesktopaction )
|
||||
CleanAction( mixericonaction )
|
||||
|
||||
#
|
||||
# Create a tags-file for easier emacs/vim-source-browsing
|
||||
# I don't know if the dependency is right...
|
||||
#
|
||||
findcommand = "find . \( -path \"*.h\" -o -path \"*.cpp\" -o -path \"*.c\" \) \! -path \"*.svn*\" \! -path \"./doc*\" \! -path \"./cache*\""
|
||||
env.Command( "tags", "", findcommand + " |xargs ctags" )
|
||||
env.Command( "TAGS", "", findcommand + " |xargs etags" )
|
||||
env.AlwaysBuild( "tags", "TAGS" )
|
||||
if 'NoCache' in dir(env):
|
||||
env.NoCache( "tags", "TAGS" )
|
||||
|
||||
# Another convinience target
|
||||
if env.GetOption( "clean" ):
|
||||
env.Execute( "rm cache/objects -Rf" )
|
||||
|
||||
#
|
||||
# vim: ts=4 sw=4 et
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
# Copyright (C) 2007-2008 Pieter Palmers
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# xml translator
|
||||
#
|
||||
|
||||
def dbusxx_xml2cpp_adaptor_action( target, source, env ):
|
||||
env.Execute( "dbusxx-xml2cpp %s --adaptor=%s" % ( source[0], target[0] ) )
|
||||
return 0
|
||||
|
||||
def dbusxx_xml2cpp_proxy_action( target, source, env ):
|
||||
env.Execute( "dbusxx-xml2cpp %s --proxy=%s" % ( source[0], target[0] ) )
|
||||
return 0
|
||||
|
||||
def generate( env, **kw ):
|
||||
env['BUILDERS']['Xml2Cpp_Adaptor'] = env.Builder(action = dbusxx_xml2cpp_adaptor_action,
|
||||
suffix = '.h', src_suffix = '.xml')
|
||||
env['BUILDERS']['Xml2Cpp_Proxy'] = env.Builder(action = dbusxx_xml2cpp_proxy_action,
|
||||
suffix = '.h', src_suffix = '.xml', single_source=True )
|
||||
|
||||
def exists( env ):
|
||||
return 1
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Astxx, the Asterisk C++ API and Utility Library.
|
||||
# Copyright (C) 2005, 2006 Matthew A. Nicholson
|
||||
# Copyright (C) 2006 Tim Blechmann
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License version 2.1 as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
from fnmatch import fnmatch
|
||||
from functools import reduce
|
||||
|
||||
def DoxyfileParse(file_contents):
|
||||
"""
|
||||
Parse a Doxygen source file and return a dictionary of all the values.
|
||||
Values will be strings and lists of strings.
|
||||
"""
|
||||
data = {}
|
||||
|
||||
import shlex
|
||||
lex = shlex.shlex(instream = file_contents.decode(), posix = True)
|
||||
lex.wordchars += "*+./-:"
|
||||
lex.whitespace = lex.whitespace.replace("\n", "")
|
||||
lex.escape = ""
|
||||
|
||||
lineno = lex.lineno
|
||||
token = lex.get_token()
|
||||
key = token # the first token should be a key
|
||||
last_token = ""
|
||||
key_token = False
|
||||
next_key = False
|
||||
new_data = True
|
||||
|
||||
def append_data(data, key, new_data, token):
|
||||
if new_data or len(data[key]) == 0:
|
||||
data[key].append(token)
|
||||
else:
|
||||
data[key][-1] += token
|
||||
|
||||
while token:
|
||||
if token in ['\n']:
|
||||
if last_token not in ['\\']:
|
||||
key_token = True
|
||||
elif token in ['\\']:
|
||||
pass
|
||||
elif key_token:
|
||||
key = token
|
||||
key_token = False
|
||||
else:
|
||||
if token == "+=":
|
||||
if not key in data:
|
||||
data[key] = list()
|
||||
elif token == "=":
|
||||
data[key] = list()
|
||||
else:
|
||||
append_data( data, key, new_data, token )
|
||||
new_data = True
|
||||
|
||||
last_token = token
|
||||
token = lex.get_token()
|
||||
|
||||
if last_token == '\\' and token != '\n':
|
||||
new_data = False
|
||||
append_data( data, key, new_data, '\\' )
|
||||
|
||||
# compress lists of len 1 into single strings
|
||||
to_pop = []
|
||||
for (k, v) in data.items():
|
||||
if len(v) == 0:
|
||||
# data.pop(k) # Shouldn't modify dictionary while looping
|
||||
to_pop.append(k)
|
||||
|
||||
# items in the following list will be kept as lists and not converted to strings
|
||||
if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS"]:
|
||||
continue
|
||||
|
||||
if len(v) == 1:
|
||||
data[k] = v[0]
|
||||
|
||||
for k in to_pop:
|
||||
data.pop(k)
|
||||
|
||||
return data
|
||||
|
||||
def DoxySourceScan(node, env, path):
|
||||
"""
|
||||
Doxygen Doxyfile source scanner. This should scan the Doxygen file and add
|
||||
any files used to generate docs to the list of source files.
|
||||
"""
|
||||
default_file_patterns = [
|
||||
'*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx',
|
||||
'*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++',
|
||||
'*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm',
|
||||
'*.py',
|
||||
]
|
||||
|
||||
default_exclude_patterns = [
|
||||
'*~',
|
||||
]
|
||||
|
||||
sources = []
|
||||
|
||||
data = DoxyfileParse(node.get_contents())
|
||||
|
||||
if data.get("RECURSIVE", "NO") == "YES":
|
||||
recursive = True
|
||||
else:
|
||||
recursive = False
|
||||
|
||||
file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
|
||||
exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
|
||||
|
||||
for node in data.get("INPUT", []):
|
||||
if os.path.isfile(node):
|
||||
sources.append(node)
|
||||
elif os.path.isdir(node):
|
||||
if recursive:
|
||||
for root, dirs, files in os.walk(node):
|
||||
for f in files:
|
||||
filename = os.path.join(root, f)
|
||||
|
||||
pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False)
|
||||
exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True)
|
||||
|
||||
if pattern_check and not exclude_check:
|
||||
sources.append(filename)
|
||||
else:
|
||||
for pattern in file_patterns:
|
||||
sources.extend(glob.glob("/".join([node, pattern])))
|
||||
|
||||
sources = map( lambda path: env.File(path), sources )
|
||||
return sources
|
||||
|
||||
|
||||
def DoxySourceScanCheck(node, env):
|
||||
"""Check if we should scan this file"""
|
||||
return os.path.isfile(node.path)
|
||||
|
||||
def DoxyEmitter(source, target, env):
|
||||
"""Doxygen Doxyfile emitter"""
|
||||
# possible output formats and their default values and output locations
|
||||
output_formats = {
|
||||
"HTML": ("YES", "html"),
|
||||
"LATEX": ("YES", "latex"),
|
||||
"RTF": ("NO", "rtf"),
|
||||
"MAN": ("YES", "man"),
|
||||
"XML": ("NO", "xml"),
|
||||
}
|
||||
|
||||
data = DoxyfileParse(source[0].get_contents())
|
||||
|
||||
targets = []
|
||||
out_dir = data.get("OUTPUT_DIRECTORY", ".")
|
||||
|
||||
# add our output locations
|
||||
for (k, v) in output_formats.items():
|
||||
if data.get("GENERATE_" + k, v[0]) == "YES":
|
||||
targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) )
|
||||
|
||||
# don't clobber targets
|
||||
for node in targets:
|
||||
env.Precious(node)
|
||||
|
||||
# set up cleaning stuff
|
||||
for node in targets:
|
||||
env.Clean(node, node)
|
||||
|
||||
return (targets, source)
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add builders and construction variables for the
|
||||
Doxygen tool. This is currently for Doxygen 1.4.6.
|
||||
"""
|
||||
doxyfile_scanner = env.Scanner(
|
||||
DoxySourceScan,
|
||||
"DoxySourceScan",
|
||||
scan_check = DoxySourceScanCheck,
|
||||
)
|
||||
|
||||
import SCons.Builder
|
||||
doxyfile_builder = SCons.Builder.Builder(
|
||||
action = "cd ${SOURCE.dir} && ${DOXYGEN} ${SOURCE.file}",
|
||||
emitter = DoxyEmitter,
|
||||
target_factory = env.fs.Entry,
|
||||
single_source = True,
|
||||
source_scanner = doxyfile_scanner,
|
||||
)
|
||||
|
||||
env.Append(BUILDERS = {
|
||||
'Doxygen': doxyfile_builder,
|
||||
})
|
||||
|
||||
env.AppendUnique(
|
||||
DOXYGEN = 'doxygen',
|
||||
)
|
||||
|
||||
def exists(env):
|
||||
"""
|
||||
Make sure doxygen exists.
|
||||
"""
|
||||
return env.Detect("doxygen")
|
|
@ -0,0 +1,113 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Taken from http://www.scons.org/wiki/UsingPkgConfig
|
||||
# and heavily modified
|
||||
#
|
||||
|
||||
import subprocess
|
||||
|
||||
#
|
||||
# Checks for pkg-config
|
||||
#
|
||||
def CheckForPKGConfig( context, version='0.0.0' ):
|
||||
context.Message( "Checking for pkg-config (at least version %s)... " % version )
|
||||
ret = context.TryAction( "pkg-config --atleast-pkgconfig-version=%s" %version )[0]
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
#
|
||||
# Checks for the given package with an optional version-requirement
|
||||
#
|
||||
# The flags (which can be imported into the environment by env.MergeFlags(...)
|
||||
# are exported as env['NAME_FLAGS'] where name is built by removing all +,-,.
|
||||
# and upper-casing.
|
||||
#
|
||||
def CheckForPKG( context, name, version="" ):
|
||||
name2 = name.replace("+","").replace(".","").replace("-","")
|
||||
|
||||
if version == "":
|
||||
context.Message( "Checking for %s... \t" % name )
|
||||
ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
|
||||
else:
|
||||
context.Message( "Checking for %s (%s or higher)... \t" % (name,version) )
|
||||
ret = context.TryAction( "pkg-config --atleast-version=%s '%s'" % (version,name) )[0]
|
||||
|
||||
if ret:
|
||||
context.env['%s_FLAGS' % name2.upper()] = context.env.ParseFlags("!pkg-config --cflags --libs %s" % name)
|
||||
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
#
|
||||
# Checks for the existance of the package and returns the packages flags.
|
||||
#
|
||||
# This should allow caching of the flags so that pkg-config is called only once.
|
||||
#
|
||||
def GetPKGFlags( context, name, version="" ):
|
||||
import os
|
||||
|
||||
if version == "":
|
||||
context.Message( "Checking for %s... \t" % name )
|
||||
ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
|
||||
else:
|
||||
context.Message( "Checking for %s (%s or higher)... \t" % (name,version) )
|
||||
ret = context.TryAction( "pkg-config --atleast-version=%s '%s'" % (version,name) )[0]
|
||||
|
||||
if not ret:
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
out = subprocess.Popen(['pkg-config', '--cflags', '--libs', name], stdout=subprocess.PIPE)
|
||||
ret = out.stdout.read()
|
||||
|
||||
context.Result( True )
|
||||
return ret
|
||||
|
||||
#
|
||||
# Checks for the existance of the package and returns the value of the specified variable.
|
||||
#
|
||||
def GetPKGVariable( context, name, variable ):
|
||||
import os
|
||||
|
||||
context.Message( "Checking for variable %s in package %s... \t" % (variable,name) )
|
||||
|
||||
ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
|
||||
if not ret:
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
out = subprocess.Popen(['pkg-config', '--variable=%s' % variable, name], stdout=subprocess.PIPE)
|
||||
ret = out.stdout.read()
|
||||
|
||||
context.Result( True )
|
||||
return ret
|
||||
|
||||
def generate( env, **kw ):
|
||||
env['PKGCONFIG_TESTS' ] = { 'CheckForPKGConfig' : CheckForPKGConfig, 'CheckForPKG' : CheckForPKG, 'GetPKGFlags' : GetPKGFlags, 'GetPKGVariable' : GetPKGVariable }
|
||||
|
||||
def exists( env ):
|
||||
return 1
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import imp
|
||||
|
||||
def pyuic_action( target, source, env ):
|
||||
env.Execute( "pyuic " + str( source[0] ) + " > " + str( target[0] ) )
|
||||
return 0
|
||||
|
||||
def pyuic_string( target, source, env ):
|
||||
return "building '%s' from '%s'" % ( str(target[0]), str( source[0] ) )
|
||||
|
||||
def PyQtCheck( context ):
|
||||
context.Message( "Checking for pyuic (by checking for the python module pyqtconfig) " )
|
||||
ret = True
|
||||
try:
|
||||
imp.find_module( "pyqtconfig" )
|
||||
except ImportError:
|
||||
ret = False
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
def generate( env, **kw ):
|
||||
env['BUILDERS']['PyUIC'] = env.Builder( action=pyuic_action, src_suffix=".ui", single_source=True )
|
||||
env['PYUIC_TESTS'] = { "PyQtCheck" : PyQtCheck }
|
||||
|
||||
|
||||
def exists( env ):
|
||||
return 1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import imp
|
||||
|
||||
def pyuic4_action( target, source, env ):
|
||||
env.Execute( "pyuic4 " + str( source[0] ) + " > " + str( target[0] ) )
|
||||
return 0
|
||||
|
||||
def pyuic4_string( target, source, env ):
|
||||
return "building '%s' from '%s'" % ( str(target[0]), str( source[0] ) )
|
||||
|
||||
def PyQt4Check( context ):
|
||||
context.Message( "Checking for pyuic4 (by checking for the python module pyqtconfig) " )
|
||||
ret = True
|
||||
try:
|
||||
imp.find_module( "pyqtconfig" )
|
||||
except ImportError:
|
||||
ret = False
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
def generate( env, **kw ):
|
||||
env['BUILDERS']['PyUIC4'] = env.Builder( action=pyuic4_action, src_suffix=".ui", single_source=True )
|
||||
env['PYUIC4_TESTS'] = { "PyQt4Check" : PyQt4Check }
|
||||
|
||||
|
||||
def exists( env ):
|
||||
return 1
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
# Copyright (C) 2017 Jonathan Woithe
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import imp
|
||||
|
||||
def pyuic5_action( target, source, env ):
|
||||
env.Execute( "pyuic5 " + str( source[0] ) + " > " + str( target[0] ) )
|
||||
return 0
|
||||
|
||||
def pyuic5_string( target, source, env ):
|
||||
return "building '%s' from '%s'" % ( str(target[0]), str( source[0] ) )
|
||||
|
||||
def PyQt5Check( context ):
|
||||
context.Message( "Checking for pyuic5 (by checking for the python module pyqtconfig) " )
|
||||
ret = True
|
||||
try:
|
||||
imp.find_module( "pyqtconfig" )
|
||||
except ImportError:
|
||||
ret = False
|
||||
context.Result( ret )
|
||||
return ret
|
||||
|
||||
def generate( env, **kw ):
|
||||
env['BUILDERS']['PyUIC5'] = env.Builder( action=pyuic5_action, src_suffix=".ui", single_source=True )
|
||||
env['PYUIC5_TESTS'] = { "PyQt5Check" : PyQt5Check }
|
||||
|
||||
|
||||
def exists( env ):
|
||||
return 1
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#
|
||||
# Taken from http://www.scons.org/wiki/ReplacementBuilder
|
||||
#
|
||||
|
||||
from string import Template
|
||||
import os
|
||||
|
||||
def replace_action(target, source, env):
|
||||
open( str(target[0]), 'w' ).write( Template( open( str(source[0]), 'r' ).read() ).safe_substitute( env ) )
|
||||
os.chmod( str(target[0]), os.stat( str(source[0]) ).st_mode )
|
||||
return 0
|
||||
|
||||
def replace_string(target, source, env):
|
||||
return "building '%s' from '%s'" % ( str(target[0]), str(source[0]) )
|
||||
|
||||
def generate(env, **kw):
|
||||
action = env.Action( replace_action, replace_string )
|
||||
env['BUILDERS']['ScanReplace'] = env.Builder( action=action, src_suffix='.in', single_source=True )
|
||||
|
||||
def exists(env):
|
||||
return 1
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
/* config.h.in. */
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#define BINDIR "$BINDIR"
|
||||
#define LIBDIR "$LIBDIR"
|
||||
#define SHAREDIR "$SHAREDIR"
|
||||
|
||||
/* configuration file locations */
|
||||
#define USER_CONFIG_FILE "$USER_CONFIG_FILE"
|
||||
#define SYSTEM_CONFIG_FILE "$SYSTEM_CONFIG_FILE"
|
||||
|
||||
/* Define indicating availability of lrint() */
|
||||
#define HAVE_LRINT $HAVE_LRINT
|
||||
|
||||
/* Define indicatin availability of lrintf() */
|
||||
#define HAVE_LRINTF $HAVE_LRINTF
|
||||
|
||||
// serialization
|
||||
#define SERIALIZE_USE_EXPAT $SERIALIZE_USE_EXPAT
|
||||
|
||||
#define CACHEDIR "$CACHEDIR"
|
||||
|
||||
// discovery
|
||||
#define ENABLE_DISCOVERY_CACHE 1
|
||||
|
||||
// watchdog
|
||||
#define WATCHDOG_DEFAULT_CHECK_INTERVAL_USECS (1000*1000*4)
|
||||
#define WATCHDOG_DEFAULT_RUN_REALTIME 1
|
||||
#define WATCHDOG_DEFAULT_PRIORITY 98
|
||||
|
||||
// threading
|
||||
#define THREAD_MAX_RTPRIO 98
|
||||
#define THREAD_MIN_RTPRIO 1
|
||||
|
||||
// time
|
||||
|
||||
// we should be using absolute clock_nanosleep
|
||||
// but on my system it causes a problem on shutdown.
|
||||
#define USE_ABSOLUTE_NANOSLEEP 1
|
||||
|
||||
// 1394 service constants
|
||||
#define IEEE1394SERVICE_USE_CYCLETIMER_DLL 1
|
||||
#define IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC 200000
|
||||
#define IEEE1394SERVICE_CYCLETIMER_DLL_BANDWIDTH_HZ 0.5
|
||||
#define IEEE1394SERVICE_MAX_FIREWIRE_PORTS 4
|
||||
#define IEEE1394SERVICE_MIN_SPLIT_TIMEOUT_USECS 1000000
|
||||
|
||||
#define IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME 1
|
||||
#define IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO 1
|
||||
|
||||
// config rom read wait interval
|
||||
#define IEEE1394SERVICE_CONFIGROM_READ_WAIT_USECS 1000
|
||||
|
||||
// FCP defines
|
||||
#define IEEE1394SERVICE_FCP_MAX_TRIES 2
|
||||
#define IEEE1394SERVICE_FCP_SLEEP_BETWEEN_FAILURES_USECS 1000
|
||||
#define IEEE1394SERVICE_FCP_POLL_TIMEOUT_MSEC 200
|
||||
#define IEEE1394SERVICE_FCP_RESPONSE_TIMEOUT_USEC 200000
|
||||
|
||||
// The current version of libiec61883 doesn't seem to calculate
|
||||
// the bandwidth correctly. Defining this to non-zero skips
|
||||
// bandwidth allocation when doing CMP connections.
|
||||
#define IEEE1394SERVICE_SKIP_IEC61883_BANDWIDTH_ALLOCATION 1
|
||||
|
||||
#define MINIMUM_INTERRUPTS_PER_PERIOD 2U
|
||||
|
||||
// These are the result of a lot of trial and error
|
||||
// due to weirdness in the kernel layer
|
||||
#define MAX_XMIT_PACKET_SIZE (2048-16)
|
||||
#define MIN_XMIT_PACKET_SIZE 72
|
||||
#define MAX_XMIT_NB_BUFFERS 128
|
||||
#define MAX_RECV_NB_BUFFERS 128
|
||||
#define MIN_RECV_PACKET_SIZE 72
|
||||
|
||||
// the default ISO receive mode.
|
||||
// 0 = auto, 1 = packet-per-buffer, 2 = bufferfill.
|
||||
// 'auto' will automatically choose the mode that is expected
|
||||
// to perform best for the given situation. For large periods
|
||||
// this is 'bufferfill' mode, for small periods this is
|
||||
// 'packet-per-buffer' mode. The 'BUFFERFILL_MODE_THRESHOLD'
|
||||
// defines what a 'large period' is.
|
||||
#define DEFAULT_ISO_RECEIVE_MODE 0
|
||||
|
||||
// the number of packets required to fill one period from which
|
||||
// the bufferfill mode is to be used
|
||||
#define BUFFERFILL_MODE_THRESHOLD 64
|
||||
|
||||
|
||||
#define ISOHANDLER_FLUSH_BEFORE_ITERATE 0
|
||||
|
||||
#define ISOHANDLER_DEATH_DETECT_TIMEOUT_USECS 1000000LL
|
||||
|
||||
#define ISOHANDLER_CHECK_CTR_RECONSTRUCTION 1
|
||||
|
||||
#define ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT 16
|
||||
#define ISOHANDLERMANAGER_MAX_STREAMS_PER_ISOTHREAD 16
|
||||
|
||||
// The best setup is if the receive handlers have lower priority
|
||||
// than the client thread since that ensures that as soon as we
|
||||
// received sufficient frames, the client thread runs.
|
||||
// The transmit thread should have higher priority to ensure that
|
||||
// all available data is flushed to the ISO kernel buffers as
|
||||
// soon as possible
|
||||
// At this moment, the jack backend uses base+5 to init ffado
|
||||
// prio
|
||||
#define ISOHANDLERMANAGER_ISO_PRIO_INCREASE 0
|
||||
#define ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV -1
|
||||
#define ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT 1
|
||||
|
||||
// the timeout for ISO activity on any thread
|
||||
// NOTE: don't make this 0
|
||||
#define ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS 1000000LL
|
||||
|
||||
// allows to add some processing margin. This shifts the time
|
||||
// at which the buffer is transfer()'ed, making things somewhat
|
||||
// more robust. It should be noted though that shifting the transfer
|
||||
// time to a later time instant also causes the xmit buffer fill to be
|
||||
// lower on average. This can be counteracted by increasing the
|
||||
// STREAMPROCESSORMANAGER_XMIT_PREBUFFER_FRAMES option
|
||||
#define STREAMPROCESSORMANAGER_SIGNAL_DELAY_TICKS (3072*0)
|
||||
|
||||
// the number of frames that we prebuffer in the 1394 ISO layer
|
||||
// this adds directly to the roundtrip latency
|
||||
#define STREAMPROCESSORMANAGER_XMIT_PREBUFFER_FRAMES 100
|
||||
|
||||
// causes the waitForPeriod() call to wait until sufficient
|
||||
// data is present in the buffer such that a transfer() will
|
||||
// succeed. Normally we wait for the period of time that theoretically
|
||||
// would mean that his is true. However sometimes the kernel hasn't
|
||||
// flushed everything to userspace (or the card hasn't IRQ'd).
|
||||
// the side-effect of this is some jitter in the return timing
|
||||
// whenever this occurs.
|
||||
#define STREAMPROCESSORMANAGER_ALLOW_DELAYED_PERIOD_SIGNAL 1
|
||||
|
||||
// startup control
|
||||
#define STREAMPROCESSORMANAGER_CYCLES_FOR_DRYRUN 40000
|
||||
#define STREAMPROCESSORMANAGER_CYCLES_FOR_STARTUP 200
|
||||
#define STREAMPROCESSORMANAGER_PRESTART_CYCLES_FOR_XMIT 20
|
||||
#define STREAMPROCESSORMANAGER_PRESTART_CYCLES_FOR_RECV 0
|
||||
#define STREAMPROCESSORMANAGER_SYNCSTART_TRIES 10
|
||||
#define STREAMPROCESSORMANAGER_SYNC_WAIT_TIME_MSEC 200
|
||||
#define STREAMPROCESSORMANAGER_NB_ALIGN_TRIES 40
|
||||
#define STREAMPROCESSORMANAGER_ALIGN_AVERAGE_TIME_MSEC 400
|
||||
|
||||
#define STREAMPROCESSORMANAGER_DYNAMIC_SYNC_DELAY 0
|
||||
|
||||
// the default bandwidth of the stream processor timestamp DLL when synchronizing (should be fast)
|
||||
#define STREAMPROCESSOR_DLL_FAST_BW_HZ 5.0
|
||||
// the default bandwidth of the stream processor timestamp DLL when streaming
|
||||
#define STREAMPROCESSOR_DLL_BW_HZ 0.1
|
||||
|
||||
// -- AMDTP options -- //
|
||||
|
||||
// in ticks
|
||||
// as per AMDTP2.1: 354.17us + 125us, but FFADO measures from the
|
||||
// packet transmission time, so subtract 125 us:
|
||||
// 354.17us @ 24.576ticks/usec = 8704 ticks
|
||||
#define AMDTP_TRANSMIT_TRANSFER_DELAY (8704U)
|
||||
|
||||
// the absolute minimum number of cycles we want to transmit
|
||||
// a packet ahead of the presentation time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by AMDTP_TRANSMIT_TRANSFER_DELAY (in ticks), but in case we
|
||||
// are too late for that, this constant defines how late we can
|
||||
// be.
|
||||
#define AMDTP_MIN_CYCLES_BEFORE_PRESENTATION 1
|
||||
|
||||
// the absolute maximum number of cycles we want to transmit
|
||||
// a packet ahead of the ideal transmit time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by AMDTP_TRANSMIT_TRANSFER_DELAY (in ticks), but we can send
|
||||
// packets early if we want to. (not completely according to spec)
|
||||
// (for spec compliance you need to specify a value of 0)
|
||||
#define AMDTP_MAX_CYCLES_TO_TRANSMIT_EARLY 1
|
||||
|
||||
// ensure that the AMDTP SP clips all float values to [-1.0..1.0]
|
||||
#define AMDTP_CLIP_FLOATS 1
|
||||
|
||||
// Allow that devices request that the AMDTP transmit SP adds
|
||||
// payload to the NO-DATA packets.
|
||||
#define AMDTP_ALLOW_PAYLOAD_IN_NODATA_XMIT 1
|
||||
|
||||
// Default setting for the payload setting if
|
||||
// AMDTP_ALLOW_PAYLOAD_IN_NODATA_XMIT is enabled. Devices can
|
||||
// explicity override this
|
||||
#define AMDTP_SEND_PAYLOAD_IN_NODATA_XMIT_BY_DEFAULT true
|
||||
|
||||
// -- MOTU options -- //
|
||||
|
||||
// the transfer delay is substracted from the ideal presentation
|
||||
// time to obtain a corrected presentation time. This values is
|
||||
// then used to stamp the packet and determine the transmission
|
||||
// time instant.
|
||||
#define MOTU_TRANSMIT_TRANSFER_DELAY (0U)
|
||||
|
||||
// the absolute minimum number of cycles we want to transmit
|
||||
// a packet ahead of the presentation time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by MOTU_TRANSMIT_TRANSFER_DELAY (in ticks), but in case we
|
||||
// are too late for that, this constant defines how late we can
|
||||
// be.
|
||||
#define MOTU_MIN_CYCLES_BEFORE_PRESENTATION 0
|
||||
|
||||
// the absolute maximum number of cycles we want to transmit
|
||||
// a packet ahead of the ideal transmit time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by MOTU_TRANSMIT_TRANSFER_DELAY (in ticks), but we can send
|
||||
// packets early if we want to.
|
||||
#define MOTU_MAX_CYCLES_TO_TRANSMIT_EARLY 2
|
||||
|
||||
// ensure that the MOTU tx SP clips all float values to [-1.0..1.0]
|
||||
#define MOTU_CLIP_FLOATS 1
|
||||
|
||||
// -- RME options -- //
|
||||
|
||||
// the transfer delay is substracted from the ideal presentation
|
||||
// time to obtain a corrected presentation time. This value is
|
||||
// then used to stamp the packet and determine the transmission
|
||||
// time instant. This is in ticks, and has been determined
|
||||
// experimentally to provide the most stability.
|
||||
#define RME_TRANSMIT_TRANSFER_DELAY (3U*TICKS_PER_CYCLE)
|
||||
|
||||
// the absolute minimum number of cycles we want to transmit
|
||||
// a packet ahead of the presentation time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by RME_TRANSMIT_TRANSFER_DELAY (in ticks), but in case we
|
||||
// are too late for that, this constant defines how late we can
|
||||
// be.
|
||||
#define RME_MIN_CYCLES_BEFORE_PRESENTATION 1
|
||||
|
||||
// the absolute maximum number of cycles we want to transmit
|
||||
// a packet ahead of the ideal transmit time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by RME_TRANSMIT_TRANSFER_DELAY (in ticks), but we can send
|
||||
// packets early if we want to.
|
||||
#define RME_MAX_CYCLES_TO_TRANSMIT_EARLY 5
|
||||
|
||||
// The transfer delay assumed for incoming packets from an RME.
|
||||
// Normally this would be the same as the transmit transfer delay.
|
||||
// This value is in ticks.
|
||||
#define RME_RECEIVE_TRANSFER_DELAY RME_TRANSMIT_TRANSFER_DELAY
|
||||
|
||||
// ensure that the RME tx SP clips all float values to [-1.0..1.0]
|
||||
#define RME_CLIP_FLOATS 1
|
||||
|
||||
// -- Digidesign options -- //
|
||||
//
|
||||
// Currently these are just verbatim copies of the values which
|
||||
// seem to work for MOTU devices. Some tweaks may well be
|
||||
// necessary once testing begins with real devices.
|
||||
|
||||
// the transfer delay is substracted from the ideal presentation
|
||||
// time to obtain a corrected presentation time. This values is
|
||||
// then used to stamp the packet and determine the transmission
|
||||
// time instant.
|
||||
#define DIGIDESIGN_TRANSMIT_TRANSFER_DELAY (0U)
|
||||
|
||||
// the absolute minimum number of cycles we want to transmit
|
||||
// a packet ahead of the presentation time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by DIGIDESIGN_TRANSMIT_TRANSFER_DELAY (in ticks), but
|
||||
// in case we are too late for that, this constant defines how
|
||||
// late we can be.
|
||||
#define DIGIDESIGN_MIN_CYCLES_BEFORE_PRESENTATION 0
|
||||
|
||||
// the absolute maximum number of cycles we want to transmit
|
||||
// a packet ahead of the ideal transmit time. The nominal time
|
||||
// the packet is transmitted ahead of the presentation time is
|
||||
// given by DIGIDESIGN_TRANSMIT_TRANSFER_DELAY (in ticks), but
|
||||
// we can send packets early if we want to.
|
||||
#define DIGIDESIGN_MAX_CYCLES_TO_TRANSMIT_EARLY 2
|
||||
|
||||
// ensure that the DIGIDESIGN tx SP clips all float values to [-1.0..1.0]
|
||||
#define DIGIDESIGN_CLIP_FLOATS 1
|
||||
|
||||
/// The unavoidable device specific hacks
|
||||
|
||||
// Use the information in the music plug instead of that in the
|
||||
// cluster info block for the stream configuration. Should not
|
||||
// be necessary
|
||||
#define AVC_STREAMCONFIG_USE_MUSICPLUG 0
|
||||
|
||||
#endif // CONFIG_H
|
|
@ -0,0 +1,46 @@
|
|||
/* config_debug.h.in. */
|
||||
#ifndef CONFIG_DEBUG_H
|
||||
#define CONFIG_DEBUG_H
|
||||
|
||||
// use a RT-safe message buffer for debug output
|
||||
// useful to disable this when the code aborts/segfaults to
|
||||
// not lose debug output. should be enabled though.
|
||||
#define DEBUG_USE_MESSAGE_BUFFER 1
|
||||
// max message length in the debug messagebuffer
|
||||
#define DEBUG_MAX_MESSAGE_LENGTH 2048
|
||||
// number of messages in the debug messagebuffer (power of two)
|
||||
#define DEBUG_MB_BUFFERS 1024
|
||||
|
||||
// use an RT thread for reading out the messagebuffer.
|
||||
// can reduce the number of buffer xruns, and
|
||||
// avoids priority inversion issues
|
||||
#define DEBUG_MESSAGE_BUFFER_REALTIME 1
|
||||
#define DEBUG_MESSAGE_BUFFER_REALTIME_PRIO 1
|
||||
|
||||
// When a write can't get the buffer lock, how many times
|
||||
// should it retry, and wait how long between retries?
|
||||
#define DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NTRIES 2
|
||||
#define DEBUG_MESSAGE_BUFFER_COLLISION_WAIT_NSEC 50000
|
||||
|
||||
// support a debug backlog
|
||||
// note that this does not influence non-debug builds
|
||||
#define DEBUG_BACKLOG_SUPPORT 0
|
||||
// number of messages in the backlog buffer (power of two)
|
||||
#define DEBUG_BACKLOG_MB_BUFFERS 64
|
||||
|
||||
// support backtrace debugging
|
||||
// note that this does not influence non-debug builds
|
||||
#define DEBUG_BACKTRACE_SUPPORT 0
|
||||
// max length of backtrace
|
||||
#define DEBUG_MAX_BACKTRACE_LENGTH 8
|
||||
// max amount of function pointers to keep track of
|
||||
#define DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN 64
|
||||
|
||||
// lock debugging
|
||||
#define DEBUG_LOCK_COLLISION_TRACING 0
|
||||
|
||||
// make this zero to disable the most extreme
|
||||
// debug logging in the critical sections
|
||||
#define DEBUG_EXTREME_ENABLE 0
|
||||
|
||||
#endif // CONFIG_DEBUG_H
|
|
@ -0,0 +1,861 @@
|
|||
device_definitions = (
|
||||
{
|
||||
vendorid = 0x00000f;
|
||||
modelid = 0x00010065;
|
||||
vendorname = "Mackie";
|
||||
modelname = "Onyx FireWire";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # Added by arnonym from ffado-mixers list
|
||||
vendorid = 0x00000f;
|
||||
modelid = 0x00010067;
|
||||
vendorname = "Mackie";
|
||||
modelname = "Onyx FireWire";
|
||||
driver = "BEBOB";
|
||||
mixer = "MackieOnyx";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # Added by yellius
|
||||
vendorid = 0x0022E;
|
||||
modelid = 0x10067;
|
||||
vendorname = "Tascam";
|
||||
modelname = "IFFWDM";
|
||||
driver = "BEBOB";
|
||||
},
|
||||
{ # IDs provided by Travis Kepley
|
||||
vendorid = 0x000ff2;
|
||||
modelid = 0x000006;
|
||||
vendorname = "Loud Technologies Inc.";
|
||||
modelname = "Onyx 1640i (DICE)";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # IDs provided by Melanie Bernkopf. Mixer entry from Scott Martin.
|
||||
vendorid = 0x000ff2;
|
||||
modelid = 0x000007;
|
||||
vendorname = "Loud Technologies Inc.";
|
||||
modelname = "Onyx Blackbird";
|
||||
driver = "DICE";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
},
|
||||
{ # IDs provided by Steven Tonge
|
||||
vendorid = 0x000ff2;
|
||||
modelid = 0x001640;
|
||||
vendorname = "Loud Technologies Inc.";
|
||||
modelname = "Onyx 1640i (Oxford)";
|
||||
driver = "OXFORD";
|
||||
# This transfer delay was tested at 48 kHz, as per
|
||||
# http://sourceforge.net/p/ffado/mailman/message/26964819/
|
||||
xmit_transfer_delay = 12800;
|
||||
},
|
||||
{ # entries provided by Holger Dehnhardt
|
||||
vendorid = 0x000ff2;
|
||||
modelid = 0x081216;
|
||||
vendorname = "Loud Technologies Inc.";
|
||||
modelname = "Onyx-i";
|
||||
driver = "OXFORD";
|
||||
xmit_transfer_delay = 11776;
|
||||
},
|
||||
{ # IDs from Geoff Beasley.
|
||||
vendorid = 0x001564;
|
||||
modelid = 0x00000006;
|
||||
vendorname = "Behringer";
|
||||
modelname = "X32";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # IDs from Tony Rocco.
|
||||
vendorid = 0x001564;
|
||||
modelid = 0x00001604;
|
||||
vendorname = "Behringer";
|
||||
modelname = "UFX-1604 mixer";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x0003db;
|
||||
modelid = 0x00010048;
|
||||
vendorname = "Apogee Electronics";
|
||||
modelname = "Rosetta 200";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # From Greg Dorian
|
||||
vendorid = 0x0003db;
|
||||
modelid = 0x01dddd;
|
||||
vendorname = "Apogee";
|
||||
modelname = "Duet";
|
||||
driver = "OXFORD";
|
||||
},
|
||||
{
|
||||
vendorid = 0x0007f5;
|
||||
modelid = 0x00010048;
|
||||
vendorname = "BridgeCo";
|
||||
modelname = "RD Audio1";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x0007f5;
|
||||
modelid = 0x00010049;
|
||||
vendorname = "BridgeCo";
|
||||
modelname = "Audio 5";
|
||||
driver = "BEBOB";
|
||||
mixer = "BCoAudio5Control";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00010000;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "FIREBOX";
|
||||
driver = "BEBOB";
|
||||
mixer = "Presonus_Firebox";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00010001;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "Inspire1394";
|
||||
driver = "BEBOB";
|
||||
mixer = "Presonus_Inspire1394";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00010066;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "FirePOD";
|
||||
driver = "BEBOB";
|
||||
mixer = "Presonus_FP10";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # Presonus Firestudio 26x26, Bob Hamil via jaimes on the forums
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00000008;
|
||||
vendorname = "Presonus";
|
||||
modelname = "Firestudio 26x26";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Presonus Firestudio Project, from Walt Baldwin
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x0000000b;
|
||||
vendorname = "Presonus";
|
||||
modelname = "Firestudio Project";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Presonus Firestudio Tube, from Tobi Kraus
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x0000000c;
|
||||
vendorname = "Presonus";
|
||||
modelname = "Firestudio Tube";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Entry for Firestudio mobile provided by "Pule" via the forums.
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00000011;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "Firestudio Mobile";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Entry for StudioLive 2442, from Walt Baldwin
|
||||
vendorid = 0x00000A92;
|
||||
modelid = 0x00000012;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "STUDIOLIVE_2442";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Entry for StudioLive 1602, from Ulrich-Lorenz Schluter
|
||||
vendorid = 0x00000A92;
|
||||
modelid = 0x00000013;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "STUDIOLIVE_1602";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Entry for Studiolive 32.4.2, from Karl Swisher
|
||||
vendorid = 0x00000a92;
|
||||
modelid = 0x00000014;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "STUDIOLIVE_3242_mk2";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000aac;
|
||||
modelid = 0x00000003;
|
||||
vendorname = "TerraTec Electronic GmbH";
|
||||
modelname = "Phase 88 FW";
|
||||
driver = "BEBOB";
|
||||
mixer = "Phase88Control";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000aac;
|
||||
modelid = 0x00000004;
|
||||
vendorname = "TerraTec Electronic GmbH";
|
||||
modelname = "Phase X24 FW (model version 4)";
|
||||
driver = "BEBOB";
|
||||
mixer = "Phase24Control";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000aac;
|
||||
modelid = 0x00000007;
|
||||
vendorname = "TerraTec Electronic GmbH";
|
||||
modelname = "Phase X24 FW (model version 7)";
|
||||
driver = "BEBOB";
|
||||
mixer = "Phase24Control";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000f1b;
|
||||
modelid = 0x00010064;
|
||||
vendorname = "ESI";
|
||||
modelname = "Quatafire 610";
|
||||
driver = "BEBOB";
|
||||
mixer = "QuataFire";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
# Shalok Shalom has a Quantafire 610 which reports a different modelid.
|
||||
# The reasons for this are unknown.
|
||||
{
|
||||
vendorid = 0x000f1b;
|
||||
modelid = 0x00000210;
|
||||
vendorname = "ESI";
|
||||
modelname = "Quatafire 610 variant";
|
||||
driver = "BEBOB";
|
||||
mixer = "QuataFire";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000003;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire Pro26IO";
|
||||
driver = "BEBOB";
|
||||
mixer = "SaffirePro";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000006;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire Pro10IO";
|
||||
driver = "BEBOB";
|
||||
mixer = "SaffirePro";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000000;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire (LE)";
|
||||
driver = "BEBOB";
|
||||
mixer = "Saffire";
|
||||
cmd_interval_time = 10000;
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x0040ab;
|
||||
modelid = 0x00010049;
|
||||
vendorname = "EDIROL";
|
||||
modelname = "FA-66";
|
||||
driver = "BEBOB";
|
||||
mixer = "EdirolFa66Control";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x0040ab;
|
||||
modelid = 0x00010048;
|
||||
vendorname = "EDIROL";
|
||||
modelname = "FA-101";
|
||||
driver = "BEBOB";
|
||||
mixer = "EdirolFa101Control";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # Added by Mark Brand (orania)
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x0000000a;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "Ozonic";
|
||||
driver = "BEBOB";
|
||||
mixer = "MAudio_BeBoB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00010062;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "FW Solo";
|
||||
driver = "BEBOB";
|
||||
mixer = "MAudio_BeBoB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00010081;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "NRV10";
|
||||
driver = "BEBOB";
|
||||
# no mixer
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00010060;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "FW Audiophile";
|
||||
driver = "BEBOB";
|
||||
mixer = "MAudio_BeBoB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00010046;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "FW 410";
|
||||
driver = "BEBOB";
|
||||
mixer = "MAudio_BeBoB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
// experimental for mixer functionality
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00010071;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "FW 1814";
|
||||
driver = "BEBOB";
|
||||
mixer = "MAudio_BeBoB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
// experimental for mixer functionality
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00010091;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "ProjectMix I/O";
|
||||
driver = "BEBOB";
|
||||
mixer = "MAudio_BeBoB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x000100A1;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "ProFire Lightbridge";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00000010;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "ProFire 2626";
|
||||
driver = "DICE";
|
||||
mixer = "Profire2626";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000d6c;
|
||||
modelid = 0x00000011;
|
||||
vendorname = "M-Audio";
|
||||
modelname = "ProFire 610";
|
||||
driver = "DICE";
|
||||
mixer = "Profire2626";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000aac;
|
||||
modelid = 0x00000002;
|
||||
vendorname = "Acoustic Reality";
|
||||
modelname = "eAR Master One";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x0000000A;
|
||||
modelid = 0x00030000;
|
||||
vendorname = "CME";
|
||||
modelname = "Matrix K FW";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAF2;
|
||||
vendorname = "Echo";
|
||||
modelname = "AudioFire2";
|
||||
driver = "FIREWORKS";
|
||||
mixer = "AudioFire";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAF4;
|
||||
vendorname = "Echo";
|
||||
modelname = "AudioFire4";
|
||||
driver = "FIREWORKS";
|
||||
mixer = "AudioFire";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAF8;
|
||||
vendorname = "Echo";
|
||||
modelname = "AudioFire8";
|
||||
driver = "FIREWORKS";
|
||||
mixer = "AudioFire";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAF9;
|
||||
vendorname = "Echo";
|
||||
modelname = "AudioFire8a";
|
||||
driver = "FIREWORKS";
|
||||
mixer = "AudioFire";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAF12;
|
||||
vendorname = "Echo";
|
||||
modelname = "AudioFire12";
|
||||
driver = "FIREWORKS";
|
||||
mixer = "AudioFire";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAF12D;
|
||||
vendorname = "Echo";
|
||||
modelname = "AudioFire12HD";
|
||||
driver = "FIREWORKS";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xF8;
|
||||
vendorname = "Echo";
|
||||
modelname = "Fireworks 8";
|
||||
driver = "FIREWORKS";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1486;
|
||||
modelid = 0xAFD1;
|
||||
vendorname = "Echo";
|
||||
modelname = "FW HDMI";
|
||||
driver = "FIREWORKS";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0xFF2;
|
||||
modelid = 0x400F;
|
||||
vendorname = "Mackie";
|
||||
modelname = "Onyx 400F";
|
||||
driver = "FIREWORKS";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0xFF2;
|
||||
modelid = 0x1200F;
|
||||
vendorname = "Mackie";
|
||||
modelname = "Onyx 1200F";
|
||||
driver = "FIREWORKS";
|
||||
xmit_max_cycles_early_transmit = 2;
|
||||
},
|
||||
{
|
||||
vendorid = 0x1564;
|
||||
modelid = 0xFC22;
|
||||
vendorname = "Behringer";
|
||||
modelname = "FCA202";
|
||||
driver = "OXFORD";
|
||||
},
|
||||
{
|
||||
vendorid = 0x00001260;
|
||||
modelid = 0x00001000;
|
||||
vendorname = "Stanton DJ";
|
||||
modelname = "SCS.1m";
|
||||
driver = "GENERICAVC";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
xmit_sp_dll_bw = 1.0;
|
||||
recv_sp_dll_bw = 1.0;
|
||||
},
|
||||
{ # added by arnonym from ffado-mixers list
|
||||
vendorid = 0x0001f2;
|
||||
modelid = 0x00000000;
|
||||
vendorname = "Motu";
|
||||
modelname = "All pre-mark3 devices";
|
||||
driver = "MOTU";
|
||||
mixer = "Motu";
|
||||
},
|
||||
{
|
||||
vendorid = 0x0001f2;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "Motu";
|
||||
modelname = "All mark3 devices";
|
||||
driver = "MOTU";
|
||||
mixer = "Motu_Mark3";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a35;
|
||||
# Note: RME detection code compares the modelid field against the
|
||||
# device's unit version since RME seem to use the configrom modelid
|
||||
# for other things not necessarily related to device differentiation.
|
||||
modelid = 0x0001;
|
||||
vendorname = "RME";
|
||||
modelname = "FireFace800";
|
||||
driver = "RME";
|
||||
mixer = "Rme";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a35;
|
||||
# Note: RME detection code compares the modelid field against the
|
||||
# device's unit version since RME seem to use the configrom modelid
|
||||
# for other things not necessarily related to device differentiation.
|
||||
modelid = 0x0002;
|
||||
vendorname = "RME";
|
||||
modelname = "FireFace400";
|
||||
driver = "RME";
|
||||
mixer = "Rme";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a35;
|
||||
# Note: RME detection code compares the modelid field against the
|
||||
# device's unit version since RME seem to use the configrom modelid
|
||||
# for other things not necessarily related to device differentiation.
|
||||
modelid = 0x0003;
|
||||
vendorname = "RME";
|
||||
modelname = "FireFace UFX";
|
||||
driver = "RME";
|
||||
mixer = "Rme";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a35;
|
||||
# Note: RME detection code compares the modelid field against the
|
||||
# device's unit version since RME seem to use the configrom modelid
|
||||
# for other things not necessarily related to device differentiation.
|
||||
# Unit version (0x04) provided by Florian Hanisch.
|
||||
modelid = 0x0004;
|
||||
vendorname = "RME";
|
||||
modelname = "FireFace UCX";
|
||||
driver = "RME";
|
||||
mixer = "Rme";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000a35;
|
||||
# Note: RME detection code compares the modelid field against the
|
||||
# device's unit version since RME seem to use the configrom modelid
|
||||
# for other things not necessarily related to device differentiation.
|
||||
# Unit version (0x05) provided by Florian Hofmann.
|
||||
modelid = 0x0005;
|
||||
vendorname = "RME";
|
||||
modelname = "FireFace 802";
|
||||
driver = "RME";
|
||||
mixer = "Rme";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x0001;
|
||||
vendorname = "TCAT";
|
||||
modelname = "DiceII EVM (1)";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x0002;
|
||||
vendorname = "TCAT";
|
||||
modelname = "DiceII EVM (2)";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x0004;
|
||||
vendorname = "TCAT";
|
||||
modelname = "DiceII EVM (4)";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x00000020;
|
||||
vendorname = "TC Electronic";
|
||||
modelname = "Konnekt 24D";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x00000021;
|
||||
vendorname = "TC Electronic";
|
||||
modelname = "Konnekt 8";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Details provided by "Juanramon" in a comment post on the website
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x00000022;
|
||||
vendorname = "TC Electronic";
|
||||
modelname = "Studio Konnekt 48";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x00000023;
|
||||
vendorname = "TC Electronic";
|
||||
modelname = "Konnekt Live";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x00000024;
|
||||
vendorname = "TC Electronic";
|
||||
modelname = "Desktop Konnekt 6";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000166;
|
||||
modelid = 0x00000027;
|
||||
vendorname = "TC Electronic";
|
||||
modelname = "ImpactTwin";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x000595;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "Alesis";
|
||||
modelname = "io|14";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
# The MultiMix-16 and MultiMix-12 share the same vendor/model IDs.
|
||||
# Thanks to Fourer Dominique for the information about the MultiMix-12.
|
||||
vendorid = 0x000595;
|
||||
modelid = 0x00000000;
|
||||
vendorname = "Alesis";
|
||||
modelname = "MultiMix-12 / MultiMix-16 FireWire";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Studiolive 16.4.2, provided by Johan Landman
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00000010;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "STUDIOLIVE_1642";
|
||||
driver = "DICE";
|
||||
xmit_transfer_delay = 4;
|
||||
},
|
||||
{ # Studiolive 16.0.2, provided by Kim Tore Jensen
|
||||
vendorid = 0x000a92;
|
||||
modelid = 0x00000013;
|
||||
vendorname = "PreSonus";
|
||||
modelname = "STUDIOLIVE_1602";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000005;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 40";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000007;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 24";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000008;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 24 DSP";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000009;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 14";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000012;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 26";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
# A new version of the Pro 40 has been released, described in the
|
||||
# ConfigROM as SAFFIRE_PRO_40_1. Thanks to Mathieu Picot for the info.
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x000000DE;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 40-1";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
# Casimir Westerholm has a "SAFFIRE_PRO_40_1" interface which somewhat
|
||||
# unexpectedly uses a different model ID to that which has been seen by
|
||||
# others. Thanks to Casimir for the information.
|
||||
vendorid = 0x00130e;
|
||||
modelid = 0x00000013;
|
||||
vendorname = "Focusrite";
|
||||
modelname = "Saffire PRO 40-1";
|
||||
driver = "DICE";
|
||||
mixer = "Saffire_Dice";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "ADC 2";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000002;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "Vesta";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000003;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "Minerva";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000004;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "AFI 1";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000005;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "TAG DAC1";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000006;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "INT 202";
|
||||
driver = "DICE";
|
||||
},
|
||||
{
|
||||
vendorid = 0x001C6A;
|
||||
modelid = 0x00000007;
|
||||
vendorname = "Weiss Engineering Ltd.";
|
||||
modelname = "DAC 202";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Added by david@wwns.com
|
||||
vendorid = 0x001c2d;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "FlexRadio_Systems";
|
||||
modelname = "Flex-5000";
|
||||
driver = "DICE";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # Phonic HelixBoard 24 Universal (PHHB24U), provided by Steffen Klein
|
||||
vendorid = 0x001496;
|
||||
modelid = 0x000000;
|
||||
vendorname = "Phonic";
|
||||
modelname = "HB 24U";
|
||||
driver = "BEBOB";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{
|
||||
vendorid = 0x0000A0DE;
|
||||
modelid = 0x0010000B;
|
||||
vendorname = "Yamaha";
|
||||
modelname = "GO44";
|
||||
driver = "BEBOB";
|
||||
mixer = "YamahaGo";
|
||||
},
|
||||
{ # Yamaha GO46, provided by Luis Pablo Gasparotto
|
||||
vendorid = 0x0000A0DE;
|
||||
modelid = 0x0010000C;
|
||||
vendorname = "Yamaha";
|
||||
modelname = "GO46";
|
||||
driver = "BEBOB";
|
||||
mixer = "YamahaGo";
|
||||
xmit_max_cycles_early_transmit = 4;
|
||||
},
|
||||
{ # DnR - Axum_FireWire_IO_card_16x16
|
||||
vendorid = 0x00000F64;
|
||||
modelid = 0x00000003;
|
||||
vendorname = "DnR";
|
||||
modelname = "Axum_FireWire_IO_card_16x16";
|
||||
driver = "DICE";
|
||||
},
|
||||
{ # Lexicon Onix-FW810S, provided by gerradblock
|
||||
vendorid = 0x00000FD7;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "Lexicon";
|
||||
modelname = "I-ONIX_FW810S";
|
||||
driver = "DICE";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
},
|
||||
{ # Avid Mbox 2 Pro, information provided by Yves Grenier via the ffado-user
|
||||
# mailing list.
|
||||
# Note: as of Oct 2014 FFADO requires that the device be initialised
|
||||
# under another operating system so routing and clock settings are
|
||||
# correct. When this is done and the device is transferred to Linux
|
||||
# without power cycling it, FFADO can stream audio to/from it. The
|
||||
# initialisation details need to be sorted before FFADO can claim to
|
||||
# properly support this device.
|
||||
vendorid = 0x0000A07E;
|
||||
modelid = 0x000000A9;
|
||||
vendorname = "Digidesign";
|
||||
modelname = "Mbox 2 Pro";
|
||||
driver = "BEBOB";
|
||||
# A device-specific mixer needs to be written, there being no generic
|
||||
# bebob mixer modules.
|
||||
},
|
||||
{ # Avid Mbox Pro, information provided by Niels Dettenbach.
|
||||
# Note: this entry is for future reference only. FFADO does NOT have a
|
||||
# driver for this device: as of March 2013 no Avid/Digidesign interfaces
|
||||
# are supported or usable with FFADO.
|
||||
vendorid = 0x0000A07E;
|
||||
modelid = 0x00000004;
|
||||
vendorname = "Avid";
|
||||
modelname = "Mbox 3 Pro";
|
||||
},
|
||||
{ # Allen and Heath Zed R16. Information from Brendan Pike.
|
||||
vendorid = 0x000004C4;
|
||||
modelid = 0x00000000;
|
||||
vendorname = "Allen and Heath";
|
||||
modelname = "Zed R16";
|
||||
driver = "DICE";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
},
|
||||
{ # Midas Venice F32. Information from Jano Svitok.
|
||||
vendorid = 0x0010C73F;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "Midas";
|
||||
modelname = "Venice F32";
|
||||
driver = "DICE";
|
||||
mixer = "Generic_Dice_EAP";
|
||||
},
|
||||
{ # ICON FireXon. Information from Philippe Ploquin.
|
||||
vendorid = 0x00001A9E;
|
||||
modelid = 0x00000001;
|
||||
vendorname = "ICON";
|
||||
modelname = "FireXon";
|
||||
driver = "BEBOB";
|
||||
# A device-specific mixer needs to be written, there being no generic
|
||||
# bebob mixer modules.
|
||||
}
|
||||
);
|
|
@ -0,0 +1,137 @@
|
|||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
# Copyright (C) 2007-2008 Pieter Palmers
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# from: http://www.qandr.org/quentin/writings/debscons.html
|
||||
import os
|
||||
|
||||
Import('env') # exported by parent SConstruct
|
||||
|
||||
# Here's the core info for the package
|
||||
|
||||
DEBNAME = "libffado0"
|
||||
if env['REVISION']:
|
||||
DEBVERSION = "%s-%s" % (env['VERSION'], env['REVISION'])
|
||||
else:
|
||||
DEBVERSION = env['VERSION']
|
||||
|
||||
DEBMAINT = "Pieter Palmers [pieter.palmers@ffado.org]"
|
||||
DEBARCH = "i386"
|
||||
DEBDEPENDS = "libraw1394-8 (>= 1.3.0), libiec61883-0 (>= 1.1.0), libavc1394-0 (>= 0.5.3), dbus (>= 1.1.0)" # what are we dependent on?
|
||||
DEBRECOMMENDS = "qt5-ukui-platformtheme (>= 1.0.0)"
|
||||
DEBDESC = "FFADO: FireWire audio for Linux (Development build SVN r%s)" % env['REVISION']
|
||||
|
||||
DEBFILES = [
|
||||
# Now we specify the files to be included in the .deb
|
||||
# Where they should go, and where they should be copied from.
|
||||
# If you have a lot of files, you may wish to generate this
|
||||
# list in some other way.
|
||||
("usr/lib/libffado.so", "#src/libffado.so"),
|
||||
("usr/lib/pkgconfig/libffado.pc", "#/libffado.pc"),
|
||||
("usr/include/libffado/ffado.h", "#libffado/ffado.h"),
|
||||
("usr/bin/ffado-dbus-server", "#support/dbus/ffado-dbus-server"),
|
||||
]
|
||||
|
||||
DEBFILES.append(("usr/share/libffado/ffado_driver_genericavc.txt", "#src/genericavc/ffado_driver_genericavc.txt"))
|
||||
|
||||
|
||||
if env['ENABLE_BEBOB']:
|
||||
DEBFILES.append(("usr/share/libffado/ffado_driver_bebob.txt", "#src/bebob/ffado_driver_bebob.txt"))
|
||||
DEBFILES.append(("usr/bin/ffado-bridgeco-downloader", "#support/firmware/ffado-bridgeco-downloader"))
|
||||
#DEBFILES.append(("usr/share/libffado/fw410.xml", "#src/bebob/maudio/fw410.xml"))
|
||||
#DEBFILES.append(("usr/share/libffado//fwap.xml","#src/bebob/maudio/fwap.xml"))
|
||||
#DEBFILES.append(("usr/share/libffado//refdesign.xml","#src/bebob/maudio/refdesign.xml"))
|
||||
if env['ENABLE_FIREWORKS']:
|
||||
DEBFILES.append(("usr/share/libffado/ffado_driver_fireworks.txt", "#src/fireworks/ffado_driver_fireworks.txt"))
|
||||
DEBFILES.append(("usr/bin/ffado-fireworks-downloader", "#support/firmware/ffado-fireworks-downloader"))
|
||||
if env['ENABLE_MOTU']:
|
||||
pass
|
||||
if env['ENABLE_DICE']:
|
||||
pass
|
||||
if env['ENABLE_METRIC_HALO']:
|
||||
pass
|
||||
if env['ENABLE_RME']:
|
||||
pass
|
||||
if env['ENABLE_BOUNCE']:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
# This is the debian package we're going to create
|
||||
debpkg = '#%s_%s_%s.deb' % (DEBNAME, DEBVERSION, DEBARCH)
|
||||
|
||||
# and we want it to be built when we build 'debian'
|
||||
env.Alias("debian", debpkg)
|
||||
|
||||
DEBCONTROLFILE = os.path.join(DEBNAME, "DEBIAN/control")
|
||||
|
||||
# This copies the necessary files into place into place.
|
||||
# Fortunately, SCons creates the necessary directories for us.
|
||||
for f in DEBFILES:
|
||||
# We put things in a directory named after the package
|
||||
dest = os.path.join(DEBNAME, f[0])
|
||||
# The .deb package will depend on this file
|
||||
env.Depends(debpkg, dest)
|
||||
# Copy from the the source tree.
|
||||
env.Command(dest, f[1], Copy('$TARGET','$SOURCE'))
|
||||
# The control file also depends on each source because we'd like
|
||||
# to know the total installed size of the package
|
||||
env.Depends(DEBCONTROLFILE, dest)
|
||||
|
||||
# Now to create the control file:
|
||||
|
||||
CONTROL_TEMPLATE = """
|
||||
Package: %s
|
||||
Priority: extra
|
||||
Section: misc
|
||||
Installed-Size: %s
|
||||
Maintainer: %s
|
||||
Architecture: %s
|
||||
Version: %s
|
||||
Depends: %s
|
||||
Recommends: %s
|
||||
Description: %s
|
||||
|
||||
"""
|
||||
env.Depends(debpkg,DEBCONTROLFILE )
|
||||
|
||||
# The control file should be updated when the SVN version changes
|
||||
env.Depends(DEBCONTROLFILE, env.Value(env['REVISION']))
|
||||
|
||||
# This function creates the control file from the template and info
|
||||
# specified above, and works out the final size of the package.
|
||||
def make_control(target=None, source=None, env=None):
|
||||
installed_size = 0
|
||||
for i in DEBFILES:
|
||||
installed_size += os.stat(str(env.File(i[1])))[6]
|
||||
control_info = CONTROL_TEMPLATE % (
|
||||
DEBNAME, installed_size, DEBMAINT, DEBARCH, DEBVERSION,
|
||||
DEBDEPENDS, DEBRECOMMENDS, DEBDESC)
|
||||
with open(str(target[0]), 'w') as f:
|
||||
f.write(control_info)
|
||||
|
||||
# We can generate the control file by calling make_control
|
||||
env.Command(DEBCONTROLFILE, None, make_control)
|
||||
|
||||
# And we can generate the .deb file by calling dpkg-deb
|
||||
env.Command(debpkg, DEBCONTROLFILE,
|
||||
"dpkg-deb -b %s %s" % ("deb/%s" % DEBNAME, "$TARGET"))
|
|
@ -0,0 +1,16 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
Import( 'env' )
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
# At this point BUILD_DOC is either 'all' or 'user'
|
||||
doxygen_dir_list = [env["top_srcdir"] + "/libffado"]
|
||||
if env["BUILD_DOC"] == 'all':
|
||||
doxygen_dir_list += [env["top_srcdir"] + "/src",
|
||||
env["top_srcdir"] + "/doc"]
|
||||
env["DOXYGEN_INPUT"] = " ".join(doxygen_dir_list)
|
||||
|
||||
env.ScanReplace( "reference.doxygen.in" )
|
||||
|
||||
env.Doxygen( "reference.doxygen" )
|
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
@page adding_devices Adding support for new devices to libffado
|
||||
|
||||
@author Pieter Palmers <pieterpalmers@users.sourceforge.net>
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
Device support is implemented on two levels:
|
||||
|
||||
1) Discovery & configuration
|
||||
|
||||
2) Streaming layer
|
||||
|
||||
Layer 1 is implemented by subclassing the IAvDevice interface, and adding an appropriate
|
||||
probe function to devicemanager.cpp.
|
||||
Layer 2 is implemented by subclassing the StreamProcessor class in src/libstreaming/
|
||||
|
||||
Basic operation of libffado is:
|
||||
- Create a DeviceManager that iterates over all nodes connected to the 1394 bus.
|
||||
For every node present, it tries the probeFunctions (probeBeBoB, probeMotu, ...).
|
||||
If a probefunction succeeds, the node is considered to be a freeob supported device.
|
||||
The probefunction should return a pointer to a AvDevice, i.e. a subclass of this
|
||||
interface. At this point we have access to all supported devices.
|
||||
|
||||
- When the streaming layer is started (e.g. by jackd), it will iterate over all IAvDevice's of
|
||||
the DeviceManager. For every device:
|
||||
The streaming layer will (most likely) set some config values (at this moment only the
|
||||
samplerate). Then will then request the number of iso streams the device provides using
|
||||
getStreamCount(). Most likely this will be 2 streams, one transmit and one receive.
|
||||
The next step is that for every stream a StreamProcessor is requested using
|
||||
getStreamProcessorByIndex(i) (i starts at 0). This streamprocessor is responsible for
|
||||
the translation between iso stream and audio API. A streamprocessor is a class that is
|
||||
a subclass of StreamProcessor (see the documentation of that class for more info).
|
||||
|
||||
- Once the streaming layer fetched all streamprocessors of all devices, it will proceed with
|
||||
initializing them, and setting up all support stuff (threads, iso handlers, etc...)
|
||||
|
||||
- After this initial setup, the streaming layer will ask the IAvDevice to start the streams
|
||||
on the hardware device, using startStreamByIndex(). When the streaming layer shuts down,
|
||||
it will use stopStreamByIndex() to stop the device's streams, and free up the (possibly
|
||||
allocated) bus resources.
|
||||
|
||||
\note the jackd backend also supports to specify a specific node. In that case only the
|
||||
AvDevice for that node is used, instead of iterating over all of them.
|
||||
\note Starting the hardware streams is part of the IAvDevice because this allows for a
|
||||
more generic streamprocessor for AMDTP streams. This stream format is used by
|
||||
BeBoB's, DICE-II devices, mLan devices, etc. Keeping the start/stop system
|
||||
separate from the streamprocessor allows the re-use of the streamprocessor should
|
||||
the start/stop mechanism differ.
|
||||
|
||||
In order to add support for a device to libffado, two things should be implemented:
|
||||
- an IAvDevice descendant that takes care of the device discovery & configuration
|
||||
- a StreamProcessor descendant that takes care of the device specific stream translation
|
||||
|
||||
@section discoverybaseclasses Streaming base class hierarchy and operation
|
||||
|
||||
@ref iavdevice.h "<src/iavdevice.h>" is the device interface. It should be more or less
|
||||
self-explanatory
|
||||
|
||||
@section streamingbaseclasses Streaming base class hierarchy and operation
|
||||
|
||||
This section explains the implementation details of the streaming part of libffado.
|
||||
|
||||
The following figure shows the base class diagram, and the derrived classed that implement
|
||||
the AMDTP (AM824, IEC61883-6) streaming decoders. It can come in handy when trying to understand the following sections.
|
||||
@image html class_diagram_1.png "Streaming Class Diagram"
|
||||
@image latex class_diagram_1.eps "Streaming Class Diagram"
|
||||
|
||||
The basic idea is that when the streaming layer is initialized, it creates a DeviceManager
|
||||
(not shown in the figure) and a StreamProcessorManager.
|
||||
|
||||
The DeviceManager is responsible for discovering and configuring the devices, as explained in the introduction.
|
||||
|
||||
The StreamProcessorManager will take care of the actual 'streaming'. This incorporates:
|
||||
- handling the Isochronous traffic (allocating handlers, iterating handles, ...)
|
||||
- translating the iso streams into the data format requested by the client application
|
||||
- handling all threading issues (creation/destruction, realtime behaviour, synchronisation, ...)
|
||||
- ...
|
||||
|
||||
It joins the iso side with the Audio API side.
|
||||
|
||||
To accomplish this, it consists of two parts:
|
||||
- a collection of StreamProcessor 's
|
||||
- an IsoHandlerManager instance
|
||||
|
||||
Related classes: Streaming::StreamProcessorManager
|
||||
|
||||
@subsection isoside The iso side: 1394 isochronous traffic management
|
||||
The IsoHandlerManager is responsible for the management of IsoHandlers. This means creating/destroying the handlers when needed, starting & stopping them, etc...
|
||||
An IsoHandler in its turn will serve an IsoStream. This means that the getPacket or putPacket callback of an IsoStream will be called by the IsoHandler whenever this is nescessary.
|
||||
|
||||
\note The IsoHandler and IsoStream are separate classes because in the case of multichannel Isochronous receive, one IsoHandler can serve more than one IsoStream. The distinction lies in the fact that IsoStreams are bound to a channel and an ieee1394 port, while IsoHandlers are only bound to an ieee1394 port. [multichannel receive is however not implemented yet]
|
||||
|
||||
The handling of an IsoStream by an IsoHandler can be started by registering the IsoStream with the IsoHandlerManager. The manager figures out if it has to allocate a new handler for this stream, and will do so if needed. It will also keep track of the IsoHandler-IsoStream relations and will clean up any unused IsoHandlers.
|
||||
|
||||
To summarize: if we want to handle (receive from/transmit on) a channel of an ieee1394 port, the only thing we have to do is create an IsoStream, setup its parameters and register it with the IsoHandlerManager. If we then start() the IsoHandlerManager and call its Execute() function, the IsoStream callback will be called whenever activity happens.
|
||||
|
||||
\note This abstraction is completely device independent, it only provides a mechanism to transmit or receive a certain isochronous stream. It could as well be used for video streams...
|
||||
|
||||
Related classes: Streaming::IsoStream, Streaming::IsoHandlerManager, Streaming::IsoHandler
|
||||
|
||||
@subsection audioapiside The Audio API side: port management
|
||||
|
||||
\note not all stuff described here is implemented yet.
|
||||
|
||||
|
||||
The abstraction presented at the audio side is based upon Ports. A 'Port' is an entity that has the following properties:
|
||||
|
||||
- It has an associated buffer to store 'events'. These events can be samples, midi bytes, control data, ... . The buffer can be allocated outside of the Port (external buffer) or can be allocated internally. Currently there are two buffer types available: E_PointerBuffer and E_RingBuffer.
|
||||
- E_PointerBuffer is a buffer that can be accessed using the getBufferAddress() method, i.e. by directly reading/writing to memory. It is assumed that routines using this method keep it's size in mind (can be obtained by multiplying getEventSize() and getBufferSize()). This buffer can be an external buffer or an internal buffer. It is important that both the reader and the writer use the correct data type.
|
||||
\note for this type, currently only externally attached buffers are supported.
|
||||
- E_RingBuffer is a ringbuffer that can be accessed using read/write type of calls.
|
||||
\note for the ringbuffer type, only internal buffers are supported.
|
||||
|
||||
- DataType: The datatype defines the data type of the events in a Port's buffer. This also determines the size of the events and hence (together with the setBufferSize()) the buffer size in bytes.
|
||||
|
||||
- PortType: The port type determines the type of events that is flowing through this port. Currently there are three port types: E_Audio, E_Midi, E_Control. In the future there might be more (e.g. E_AC3 or E_Adat).
|
||||
|
||||
- SignalType: The signalling type defines how the 'new event' signalling should occur for this port. Currently there are two possibilities:
|
||||
- E_PacketSignalled: The port contents should be updated every time a packet arrives. This means that the read to/write from operation of the port is to be called for every packet that arrives (i.e. from within the packet handler callback). The most obvious use is for midi ports, as it can be a problem when midi bytes are quantized to period boundaries.
|
||||
- E_PeriodSignalled: The port contents should be updated every time time one period of packets is ready. This is for audio data, as this allows the code responsible for reading/writing the Port buffers to buffer the sink/source events untill one period has arrived, and then encode/decode the events all at once from/to the Port buffer. This is a big performance boost due to locallity of data (cache) and the possibility of using SIMD instructions, especially for big buffers.
|
||||
|
||||
- Direction: A port is either a Playback or a Capture port. Playback ports are filled by the Audio API and packetized into the iso stream, Capture ports are filled by the iso stream and read out by the Audio API.
|
||||
|
||||
\note maybe someday we'll allow any access type with any buffer type, but that doesn't seem to be nescessary now.
|
||||
\note there are some relations between the DataType and the PortType. These relations should be established in the derrivative classes of Port.
|
||||
|
||||
\note one of the fishy things about Ports is the order in which you can call Port methods and change parameters. more on that later.
|
||||
|
||||
In order to facilitate the management of a collection of Ports, a PortManager class is implemented. This class implements methods like addPort(), deletePort() etc... It also allows to initialize, prepare and reset all ports in it's collection.
|
||||
|
||||
The idea is that we present a collection of ports to the Audio API side which from which it can read or to which it can write.
|
||||
|
||||
Related classes: Streaming::Port, Streaming::PortManager
|
||||
|
||||
@subsection connectingisoandaudio Connecting the iso side with the Audio API side
|
||||
The connection between the iso side and the Audio API side is done by the StreamProcessor class. This class inherits both from IsoStream and PortManager. It therefore can be registered to the IsoHandlerManager in order to receive/transmit an iso stream. It can also contain a collection of Ports that serve as a destination/source for the events in the iso stream.
|
||||
|
||||
The StreamProcessor class is an abstract class, it cannot be instantiated by itself. The classes that implement a StreamProcessor should derrive from either ReceiveStreamProcessor or TransmitStreamProcessor. These classes provide some extra code that differs between directions.
|
||||
|
||||
A ReceiveStreamProcessor implements the putPacket callback, which is called every time a packet arrives. It is supposed to buffer the events (or the decoded frames). When one period of frames can be transmitted to the Audio API, it should signal this when its isOnePeriodReady() method is called.
|
||||
|
||||
For PeriodSignalled Ports, the actual transfer from the internal buffer(s) to the Port buffers should be done in the transfer() method. This is because it is not nescessarily so that the buffers of the StreamProcessor's Ports are valid. When the transfer() method is called, the buffers are guaranteed to be valid. The jackd backend for example sets the Port buffers to an internal address before calling transfer(). This allows for a near-zero-copy transfer of the audio: the iso stream events are decoded directly into the jackd sample buffer.
|
||||
|
||||
For PacketSignalled Ports, the StreamProcessor should decode & write the events when they arrive (in the packet callback).
|
||||
|
||||
A TransmitStreamProcessor implements the getPacket method to construct packets. The rules wrt Port buffer access and internal buffering are similar to those of the ReceiveStreamProcessor.
|
||||
|
||||
A StreamProcessor can be enabled and disabled. When a StreamProcessor is disabled, it should not read from or write to it's Port buffers. However, it's putPacket or getPacket callback can be called, so especially for TransmitStreamProcessors one should make sure to generate valid packets (if the device needs them). This behaviour is because some devices need some time before they start sending data, and we want to prevent our port buffers (especially playback) from Xrun due to a StreamProcessor that is already consuming while others are not ready yet. The enable state can be tested with the m_disabled variable.
|
||||
|
||||
Closely coupled to the enable/disable functionallity is the isRunning() function. This should return true when a StreamProcessor is ready to consume or provide events.
|
||||
\note Mostly, a TransmitStreamProcessor is always 'runnable', but a ReceiveStreamProcessor only becomes running when it actually starts to receive events.
|
||||
|
||||
In order to make the streaming system work, the StreamProcessors should update the value of m_framecounter in the packet callback. For a ReceiveStreamProcessor this denotes the number of received events, for a TransmitStreamProcessor this is the number of events transmitted. Most of the time this value should be incremented by the number of frames processed in the callback. This increment should be done by calling incrementFrameCounter(nb_frames) to do this thread-safe. The framecounter will be decremented by the streaming thread.
|
||||
|
||||
A StreamProcessor also has the init(), prepare() and reset() calls, which are still to be documented (see later).
|
||||
|
||||
Related classes: Streaming::StreamProcessor, Streaming::ReceiveStreamProcessor, Streaming::TransmitStreamProcessor, Streaming::PortManager
|
||||
|
||||
@subsection mappingports Mapping Ports to IsoStreams
|
||||
The only thing not explained up till now is how the StreamProcessor knows which iso substream to decode to which port. This is done by defining device specific subclasses of the Port class. These classes inherit both from the generic Port class and from a device specific class (e.g. PortInfo). This PortInfo class contains all information the StreamProcessor needs to map the Port onto the IsoStream, or vice versa. Due to the subclassing, these new device-specific ports can be used as if they were a normal Port. An example can be found in \ref amdtpdescription .
|
||||
|
||||
@subsection puttingtogether Putting it all together
|
||||
|
||||
@note this is outdated
|
||||
|
||||
The framework is completed by introducing the StreamProcessorManager. As indicated before, this class implements a 'collection of StreamProcessors' and an IsoHandlerManager.
|
||||
|
||||
First of all, the StreamProcessorManager is a collection of StreamProcessors, hence it implements the registerStreamProcessor and unregisterStreamProcessor methods. It maintains the list of StreamProcessors under it's control. When StreamProcessors are (un)registered, they are automatically (un)registered to the IsoHandlerManager too, creating IsoHandlers to handle them. Remember that StreamProcessor is a descendant of IsoStream, and can therefore be registered to an IsoHandlerManager. This results in the fact that the iso stream the StreamProcessor is supposed to handle, will be attached to an IsoHandler.
|
||||
|
||||
Furthermore StreamProcessorManager is a child of the Runnable interface, and can therefore be used as the worker class for a Thread. A complicated sentence to say that the StreamProcessorManager will start up a thread that calls its Execute() function, which in its turn calls the IsoHandlerManager Exectute() method (hence iterating the IsoHandlers managed by the IsoHandlerManager). This thread also performs the synchronisation as described in the next paragraph.
|
||||
|
||||
The third function of the StreamProcessorManager is the synchronisation between the iso side and the Audio API side. To implement this, the class provides a wait() method that waits on a synchronisation primitive. This primitive is signalled by the thread that iterates the IsoHandlerManager. This thread will signal the primitive when all StreamProcessors indicate that they have one period ready.
|
||||
\note this condition is not perfect, but it will do for the moment
|
||||
|
||||
The Audio API should call wait(), and when it returns, should call transfer() to transfer the internal buffer contents to the Port buffers. It can then proceed to reading out these Port buffers. The near-zero-copy approach would be to call wait(), then change the Port buffer address to the client's audio buffer for that channel, and then call transfer().
|
||||
|
||||
Currently this is for PeriodSignalled Ports only. The PacketBuffered Ports require the Audio API to read/write each Port individually using read/write routines. There is no signalling for these ports. The calls to read/write are also non-blocking, meaning that the Audio API will have to contignously poll these Ports for activity. This can be done with a separate thread, possibly using a sleep() call beween Port buffer fill checks.
|
||||
\note A blocking-read/nonblocking write (and the other way around) version of access to PacketBuffered Ports is planned.
|
||||
|
||||
Related classes: Streaming::StreamProcessorManager, Streaming::IsoHandlerManager, Streaming::Port
|
||||
|
||||
@subsection callingorder Some notes on when which method is called
|
||||
It is not very clear when which method is called (init/prepare/reset/...). This is due to the fact that this isn't really 'clean' yet. Therefore it will be documented later. The source code contains some notes on this.
|
||||
|
||||
Some preliminary statements for StreamProcessor's:
|
||||
- init() should call it's parent class' init to initialize the IsoStream
|
||||
- prepare()
|
||||
- should call it's parent class' prepare first, this makes m_nb_buffers and m_period available. These are needed to allocate the internal buffer. It should then proceed to allocate it's internal buffer(s).
|
||||
- should make sure all ports are ready by calling init() and prepare() for the ports. However this can only be done after all Port parameters (buffersize, port type, ...) are set. Once a Port is init()'d, there are some parameters that cannot be changed (see Port documentation)
|
||||
- when the StreamProcessor is an TransmitStreamProcessor, it might be good to prefill internal buffers.
|
||||
- reset() is called when an xrun occurs. it should clear (& prefill) all buffers, and should also be passed on to the parent in order to reset all counters, parent classes and ports.
|
||||
|
||||
@section refimplementation Reference Implementation
|
||||
|
||||
The BeBoB discovery with the AMDTP StreamProcessor can be considered the reference implementation of this model. You can find a description of the AMDTP StreamProcessor in \ref amdtpdescription .
|
||||
|
||||
*/
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
@page amdtpdescription The AMDTP StreamProcessor
|
||||
|
||||
@author Pieter Palmers <pieterpalmers@users.sourceforge.net>
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
( still to be written )
|
||||
|
||||
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This is the main page of the FFADO reference manual, built using
|
||||
* doxygen.
|
||||
*/
|
||||
|
||||
/**
|
||||
@mainpage FFADO - Free FireWire (pro-)Audio Drivers for Linux
|
||||
|
||||
@author Pieter Palmers <pieterpalmers@users.sourceforge.net>
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
FFADO is intended as an intermediate layer between the Linux1394 kernel/userspace layer, and the various audio API's (ALSA, jack, ...) present.
|
||||
|
||||
\note this is a SVN version, therefore it is highly volatile. Certain parts of the documentation can be outdated. This documentation is also auto-generated, and it can occur that unused classes and interfaces appear in the documentation. This pollution will be cleaned up as we go along.
|
||||
|
||||
@see <http://ffado.sourceforge.net>
|
||||
|
||||
@section library Client side library
|
||||
|
||||
FFADO presents an interface that can be used to implement backends for various audio
|
||||
API's. Currently the best support is for the JACK backend. It is also intended to implement configuration applications like mixer controls etc..
|
||||
|
||||
The library API's external C interface is defined in:
|
||||
- @ref ffado.h "<libffado/ffado.h>"
|
||||
|
||||
@section devicesupport Adding support for unsupported devices
|
||||
|
||||
Initial support by FreeBoB was for BeBoB devices only, however the FFADO framework
|
||||
is usable for all FireWire audio devices.
|
||||
|
||||
Take a look at the @ref adding_devices page for a detailed description.
|
||||
|
||||
*/
|
|
@ -0,0 +1,503 @@
|
|||
Protocol details for MOTU "mark 3" devices, obtained in the first instance
|
||||
using an 828 Mk 3.
|
||||
|
||||
Version: 20100517-1
|
||||
Author: Jonathan Woithe
|
||||
|
||||
|
||||
Audio data streaming packets
|
||||
----------------------------
|
||||
|
||||
It appears the streaming packets in the "mark 3" devices use a very similar
|
||||
protocol to the earlier interfaces. Each iso packet begins with a 64-bit
|
||||
CIP header. Following this are N data blocks, where N varies according to
|
||||
the sample rate selected (8 for 1x, 16 for 2x, 32 for 4x). Each data block
|
||||
comprises a 32-bit SPH field (consisting of a standard SPH timestamp), 48
|
||||
bits of control/MIDI data and then the audio data itself. The audio data is
|
||||
sent as packed big-endian signed integer data, as for the earlier
|
||||
interfaces.
|
||||
|
||||
At 1x rates, the maximum packet size sent to the MOTU is 0x328 (808) bytes:
|
||||
8 bytes CIP header
|
||||
8 data blocks
|
||||
Each data block contains:
|
||||
4 bytes SPH timestamp
|
||||
6 bytes control/MIDI data
|
||||
90 bytes of audio data (30 channels)
|
||||
The audio data is ordered as follows: phones, analog 1-8, main out, SPDIF,
|
||||
ADAT1 1-8, ADAT2 1-8.
|
||||
|
||||
At 1x rates the MOTU sends 0x388 (904) bytes per packet, providing space
|
||||
for 34 audio channels (order to be investigated): mic/guitar 1-2, analog
|
||||
1-8, return 1-2, reverb 1-2, SPDIF, Unknown 1-2, ADAT1 1-8, ADAT2 1-8.
|
||||
|
||||
At 2x rates, packets sent to the MOTU have a maximum size of 0x4c8 (1224)
|
||||
bytes while those sent by the MOTU are 0x0588 (1416) bytes. 16 blocks are
|
||||
send in each packet. 22 channels sent to the MOTU (order to be confirmed):
|
||||
phones, analog 1-8, main out, SPDIF, ADAT1 1-4, ADAT2 1-4. There is space
|
||||
for 26 channels sent from the MOTU (order to be investigated): analog 1-8,
|
||||
mic/guitar 1-2, SPDIF, return 1-2, reverb 1-2?, ADAT1 1-4, ADAT2 1-4,
|
||||
unknown 1-2.
|
||||
|
||||
At 4x rates 0x0508 (1288) bytes are sent to the MOTU and 0x0688 (1672) are
|
||||
sent from the MOTU. For sending to the MOTU there are 32 blocks with room
|
||||
for 10 audio channels: unknown 1-2, analog 1-8. The MOTU sends 14 audio
|
||||
channels (order to be investigated): analog 1-8, mic/guitar 1-2, return 1-2,
|
||||
unknown 1-2.
|
||||
|
||||
The following matrix represents the current best guess as to the layout of
|
||||
the audio channels in the iso data. Offset refers to the number of bytes
|
||||
from the start of the data block. "?" signifies that the channel assignment
|
||||
is yet to be confirmed and/or is positioned as a result of educated
|
||||
guesswork.
|
||||
|
||||
Offset 1x Rates 2x Rates 4x Rates
|
||||
Playback Capture Playback Capture Playback Capture
|
||||
-------------------------------------------------------------------------
|
||||
10 Phones-L Mic-1? Phones-L Mic-1? Unknown-1 Mic-1?
|
||||
13 Phones-R Mic-2? Phones-R Mic-2? Unknown-2 Mic-2?
|
||||
16 Analog 1 Analog 1 Analog 1 Analog 1 Analog 1 Analog 1
|
||||
19 Analog 2 Analog 2 Analog 2 Analog 2 Analog 2 Analog 2
|
||||
22 Analog 3 Analog 3 Analog 3 Analog 3 Analog 3 Analog 3
|
||||
25 Analog 4 Analog 4 Analog 4 Analog 4 Analog 4 Analog 4
|
||||
28 Analog 5 Analog 5 Analog 5 Analog 5 Analog 5 Analog 5
|
||||
31 Analog 6 Analog 6 Analog 6 Analog 6 Analog 6 Analog 6
|
||||
34 Analog 7 Analog 7 Analog 7 Analog 7 Analog 7 Analog 7
|
||||
37 Analog 8 Analog 8 Analog 8 Analog 8 Analog 8 Analog 8
|
||||
40 MainOut-L Return-1? MainOut-L Return-1? Return-1?
|
||||
43 MainOut-R Return-2? MainOut-R Return-2? Return-2?
|
||||
46 SPDIF-1 SPDIF-1? SPDIF-1? SPDIF-1? Unknown-1
|
||||
49 SPDIF-2 SPDIF-2? SPDIF-2? SPDIF-2? Unknown-2
|
||||
52 ADAT1-1 Reverb-1? ADAT1-1? Reverb-1?
|
||||
55 ADAT1-2 Reverb-2? ADAT1-2? Reverb-2?
|
||||
58 ADAT1-3 Unknown-1? ADAT1-3? ADAT1-1?
|
||||
61 ADAT1-4 Unknown-2? ADAT1-4? ADAT1-2?
|
||||
64 ADAT1-5 ADAT1-1? ADAT2-1? ADAT1-3?
|
||||
67 ADAT1-6 ADAT1-2? ADAT2-2? ADAT1-4?
|
||||
70 ADAT1-7 ADAT1-3? ADAT2-3? ADAT2-1?
|
||||
73 ADAT1-8 ADAT1-4? ADAT2-4? ADAT2-2?
|
||||
76 ADAT2-1 ADAT1-5? ADAT2-3?
|
||||
79 ADAT2-2 ADAT1-6? ADAT2-4?
|
||||
82 ADAT2-3 ADAT1-7? Unknown-1?
|
||||
85 ADAT2-4 ADAT1-8? Unknown-2?
|
||||
88 ADAT2-5 ADAT2-1?
|
||||
91 ADAT2-6 ADAT2-2?
|
||||
94 ADAT2-7 ADAT2-3?
|
||||
97 ADAT2-8 ADAT2-4?
|
||||
100 ADAT2-5?
|
||||
103 ADAT2-6?
|
||||
106 ADAT2-7?
|
||||
109 ADAT2-8?
|
||||
------------------------------------------------------------------------
|
||||
#ch 30 34 22 26 10 14
|
||||
|
||||
When an optical port is configured in Toslink mode, the two Toslink channels
|
||||
take the place of that port's 8 ADAT channels in the data stream. That is,
|
||||
ADAT-x 1-8 are removed and in their place Toslink-A 1-2 are added. So in
|
||||
the case of 1x playback, the Toslink channels appear at offset 52, with
|
||||
ADAT-B's channels commencing at offset 58 (the total packet size in this
|
||||
case being 0x02c8 bytes).
|
||||
|
||||
Unlike previous MOTU generations, the Toslink outputs in the Mark 3 devices
|
||||
are present as channels in their own right - they do not mirror the SPDIF
|
||||
channel.
|
||||
|
||||
|
||||
Device control
|
||||
--------------
|
||||
|
||||
Optical port modes
|
||||
|
||||
The modes of the two optical ports can be controlled independently. The
|
||||
primary mechanism for this is via a quadlet write to register
|
||||
0xfffff0000c94.
|
||||
|
||||
Bit 22: optical port B output mode (0=ADAT, 1=Toslink)
|
||||
Bit 20: optical port B input mode (0=ADAT, 1=Toslink)
|
||||
Bit 18: optical port A output mode (0=ADAT, 1=Toslink)
|
||||
Bit 16: optical port A input mode (0=ADAT, 1=Toslink)
|
||||
Bit 9: optical port B output enabled (0=disabled, 1=enabled)
|
||||
Bit 8: optical port A output enabled (0=disabled, 1=enabled)
|
||||
Bit 1: optical port B input enabled (0=disabled, 1=enabled)
|
||||
Bit 0: optical port A input enabled (0=disabled, 1=enabled)
|
||||
|
||||
Other areas of the driver also appear to refresh the device status with
|
||||
writes to other registers at the time the optical mode is updated:
|
||||
0xfffff0000c04
|
||||
0xfffff0000c60 - 0xfffff0000c6c (ASCII name of clock source)
|
||||
0xfffff0000c94
|
||||
0xfffff0000b14
|
||||
0xfffff0000b38
|
||||
0xfffff0000b3c
|
||||
0xfffff0000b04
|
||||
0xfffff0000b08
|
||||
0xfffff0000b38
|
||||
0xfffff0000b3c
|
||||
0xfffff0000b1c
|
||||
It is not known whether these additional writes are necessary.
|
||||
|
||||
|
||||
Clock source control and sample rate
|
||||
|
||||
The clock source is set with a quadlet write to bits 0, 1, 3 and 4 of
|
||||
register 0xfffff0000b14. Values for bits 4-3-1-0:
|
||||
0-0-0-0 = internal
|
||||
0-0-1-0 = SMTPE
|
||||
0-0-0-1 = Word clock
|
||||
1-0-0-0 = SPDIF
|
||||
1-1-0-0 = ADAT port A / Toslink-A (depending on current optical port mode)
|
||||
1-1-0-1 = ADAT port B / Toslink-B (depending on current optical port mode)
|
||||
|
||||
The sample rate is selected using bits 10-8 of register 0xfffff0000b14:
|
||||
0x0 = 44.1 kHz
|
||||
0x1 = 48 kHz
|
||||
0x2 = 88.2 kHz
|
||||
0x3 = 96 kHz
|
||||
0x4 = 176.4 kHz
|
||||
0x5 = 192 kHz
|
||||
|
||||
Bits 25 and 24 of register 0xfffff0000b14 are used in connection with
|
||||
streaming control (see separate section). All other bits not mentioned
|
||||
are set to zero.
|
||||
|
||||
Writes to other registers (as for ADAT modes) accompany the setting of
|
||||
register 0xfffff0000b14.
|
||||
|
||||
|
||||
MainOut/Phones assign
|
||||
|
||||
Register 0xfffff0000c04 controls the MainOut assign via bits 7-4:
|
||||
0x0 = MainOut
|
||||
0x1 = Ana 1-2
|
||||
0x2 = Ana 3-4
|
||||
0x3 = Ana 5-6
|
||||
0x4 = Ana 7-8
|
||||
0x5 = SPDIF
|
||||
0x6 = Phones
|
||||
0x7 = ADAT-A 1-2 (or Toslink if ADAT-A optical out mode is Toslink)
|
||||
0x8 = ADAT-A 3-4
|
||||
0x9 = ADAT-A 5-6
|
||||
0xa = ADAT-A 7-8
|
||||
0xb = ADAT-B 1-2 (or Toslink if ADAT-B optical out mode is Toslink)
|
||||
0xc = ADAT-B 3-4
|
||||
0xd = ADAT-B 5-6
|
||||
0xe = ADAT-B 7-8
|
||||
|
||||
Bits 3-0 of register 0xfffff0000c04 control the Phones assign. The meaning
|
||||
of the bit combinations is as per the MainOut assign case.
|
||||
|
||||
Bits 11-8 of register 0xfffff0000c04 control the "Return" assign. Again,
|
||||
the meaning of the bit combinations is as per the MainOut assign case.
|
||||
|
||||
All other bits in register 0xfffff0000c04 appear to be zero at present.
|
||||
|
||||
|
||||
Streaming control
|
||||
|
||||
Bits 31 to 16 of register 0xfffff0000b00 control the streaming channels
|
||||
in the same way as for earlier MOTU devices.
|
||||
|
||||
To start streaming:
|
||||
- a value of 0x00000002 is written to register 0xfffff0000b10.
|
||||
- bit 24 of register 0xfffff0000b14 is set to 1 (other bits are set to
|
||||
their current values)
|
||||
- a bunch of other registers are written to which, given experience with
|
||||
earlier MOTU interfaces, are not strictly required
|
||||
- register 0xfffff0000c04 is polled. A result of 0x00000111 requires
|
||||
another poll. Polling stops when the value is 0x00000303.
|
||||
- register 0xfffff0000b14 is read.
|
||||
- bits 24 and 25 in register 0xfffff0000b14 are set (other bits remain
|
||||
unchanged)
|
||||
- another bunch of (possibly inconsequential) registers is written to.
|
||||
- register 0xfffff0000b14 is read again.
|
||||
- writes to the same collection of registers again.
|
||||
|
||||
To stop streaming:
|
||||
- bit 25 of register 0xfffff0000b14 is cleared (other bits remain
|
||||
unchanged; this includes leaving bit 24 set to 1)
|
||||
- register 0xfffff0000b00 is used to stop streaming in the same way as for
|
||||
earlier MOTU interfaces
|
||||
- write to other registers of potentially little value
|
||||
- register 0xfffff0000b14 has bit 24 cleared (all other bits remain
|
||||
unchanged, so bits 25 and 24 are both zero)
|
||||
- immediately, register 0xfffff0000b14 has bit 24 set (all other bits
|
||||
remain unchanged).
|
||||
- other registers are read again.
|
||||
|
||||
It appears based on this that the streaming control of the Mark3 MOTU
|
||||
devices is the same as for previous generations.
|
||||
|
||||
|
||||
CuemixFX control
|
||||
----------------
|
||||
|
||||
Control of the CuemixFX system is via writes starting at register
|
||||
0xffff00010000. Either 1, 2 or 3 quadlets are written depending on what is
|
||||
being done. Each packet includes a serial number which is incremented after
|
||||
sending each control packet. The same serial number counter is used
|
||||
regardless of the type of control packet being sent.
|
||||
|
||||
|
||||
CuemixFX heartbeats
|
||||
-------------------
|
||||
|
||||
The MOTU periodically sends a heartbeat packet back to the PC. This is sent
|
||||
to address 0x000300000000 and consists of a single quadlet length write
|
||||
block request of the following form:
|
||||
|
||||
00 aa 00 00
|
||||
|
||||
"aa" is the serial number ranging from 0x00 to 0xff.
|
||||
|
||||
It appears that heartbeat packets are sometimes sent to the MOTU. These take
|
||||
the form of single-quadlet writes to the CuemixFX address. The quadlet
|
||||
takes the following form:
|
||||
|
||||
02 aa 00 00
|
||||
|
||||
"aa" is the serial number of the packet ranging from 0x00 to 0xff.
|
||||
|
||||
It's not yet certain what purpose these packets serve and whether they are
|
||||
in fact necessary. It is also not yet known whether the MOTU or the PC
|
||||
initiates the process (that is, which one sends a packet with a given serial
|
||||
number first).
|
||||
|
||||
|
||||
Pedal events
|
||||
------------
|
||||
|
||||
When a pedal event occurs the MOTU sends a quadlet write request to address
|
||||
0x000300000000 on the PC. The format of the quadlet is as follows.
|
||||
|
||||
bb 00 00 c2
|
||||
|
||||
"bb" is 0 for a "pedal up" event and 1 for a "pedal down" event. The pedal
|
||||
is "down" when the pedal switch is closed.
|
||||
|
||||
|
||||
CuemixFX variable controls
|
||||
--------------------------
|
||||
|
||||
The control of continuously variable controls (for example, faders, pan
|
||||
controls) is by way of 3-quadlet writes to the CuemixFX register. The
|
||||
format of these writes is as follows:
|
||||
|
||||
02 aa 66 bb - cc dd ee v1 - v2 v3 v4 00
|
||||
|
||||
where:
|
||||
aa = packet serial number as previously described
|
||||
bb = the bus/channel number (0x00 = mix bus 1, mic 1)
|
||||
cc-dd-ee = the key of the control being changed
|
||||
v1-v4 = the value being written. v1 is the most-significant byte. The
|
||||
value appears to be a 32-bit float. That is, v1..v4 is a big
|
||||
endian 32-bit float.
|
||||
|
||||
Keys presently identified are as follows.
|
||||
|
||||
00-01-02 = Bus reverb send (0-0x3f800000)
|
||||
00-0c-01 = Input reverb send (0 ("-inf") to 0x3f800000 ("0 dB")). bb is
|
||||
the zero-based input channel index for this key.
|
||||
01-01-02 = Bus reverb return (0-0x3f800000)
|
||||
02-00-01 = Input trim control (mic inputs: 0 ("+0 dB") - 0x42540000 ("+53
|
||||
dB"); line inputs: 0xc2c00000 ("-96") - 0x41b00000 ("+22")).
|
||||
For this key, bb is the zero-based channel index.
|
||||
02-00-02 = Bus master fader
|
||||
02-mm-02 = Channel pan. mm is the standard channel index. Values range
|
||||
from 0xbf800000 (L) to 0x3f800000 (R).
|
||||
03-mm-02 = Channel fader. mm is the channel index starting at 0x02 for
|
||||
the first channel (on the 828-mk3 this is mic 1). Values range
|
||||
from 0 (-inf) to 0x3f800000 (0 dB).
|
||||
05-mm-02 = Channel balance (active only for stereo paired channels).
|
||||
Values are from 0xbf800000 ("-1") to 0x3f800000 ("1").
|
||||
06-mm-02 = Channel width (active only for MS-paired channels). Values are
|
||||
from 0 ("0") to 0x3f800000 ("1").
|
||||
07-00-00 = Focus select. v4 = 0x01 for channel select, 0x03 for bus
|
||||
select. For channel select one is focusing the actual input,
|
||||
not the channel in the current bus. Therefore the bus select
|
||||
byte (bb) is always zero for this key. v1 = 0x00 (mic 1 or 2),
|
||||
0x01 (ana 1 or 2) and so forth for channel pairs. Bus focus
|
||||
focuses the output assigned to the bus, not the bus itself. v1
|
||||
in this case is 0x00 for Main, 0x01 for Analog 1-2 and so
|
||||
forth. Again the bus select byte is always zero.
|
||||
v2 and v3 are always zero.
|
||||
|
||||
Channel EQ controls:
|
||||
02-yy-01 = Input EQ frequency. Value range 0x41a00001 (20 Hz) to
|
||||
0x469c4004 (20 kHz)
|
||||
03-yy-01 = Input EQ gain. Value range 0xc1a00000 (-20 dB) to 0x41a00000
|
||||
(+20 dB)
|
||||
04-yy-01 = Input EQ Q. Value range 0x3c23d70a (0.01) to 0x40400000 (3.00)
|
||||
02-yy-03 = Output EQ frequency. Value range 0x41a00001 (20 Hz) to
|
||||
0x469c4004 (20 kHz)
|
||||
03-yy-03 = Output EQ gain. Value range 0xc1a00000 (-20 dB) to 0x41a00000
|
||||
(+20 dB)
|
||||
04-yy-03 = Output EQ Q. Value range 0x3c23d70a (0.01) to 0x40400000 (3.00)
|
||||
The EQ number ("yy" in this table) is as follows:
|
||||
02 = EQ F
|
||||
03 = EQ A
|
||||
04 = EQ C
|
||||
05 = EQ D
|
||||
06 = EQ E
|
||||
07 = EQ B
|
||||
80 = EQ G
|
||||
|
||||
Input channel dynamics controls:
|
||||
01-0a-01 = compressor threshold. Value range 0xc2400000 (-48 dB) to
|
||||
0x00000000 (0 dB).
|
||||
02-0a-01 = compressor ratio. Value range 0x3f800000 (1.0:1) to
|
||||
0x41200000 (10.0:1).
|
||||
03-0a-01 = compressor attack. Value range 0x41200000 (10 ms) to
|
||||
0x42c80000 (100 ms)
|
||||
04-0a-01 = compressor release. Value range 0x41200000 (10 ms) to
|
||||
0x44fa0000 (2 s)
|
||||
05-0a-01 = compressor trim. Value range 0xc0c00000 (-6 dB) to
|
||||
0x00000000 (0 dB)
|
||||
02-0b-01 = leveler makeup gain. Value range 0x00000000 to 0x42c80000.
|
||||
03-0b-01 = leveler gain reduction. Value range 0x00000000 to 0x42c80000.
|
||||
|
||||
Output channel dynamics controls:
|
||||
01-09-03 = compressor threshold. Value range 0xc2400000 (-48 dB) to
|
||||
0x00000000 (0 dB).
|
||||
02-09-03 = compressor ratio. Value range 0x3f800000 (1.0:1) to
|
||||
0x41200000 (10.0:1).
|
||||
03-09-03 = compressor attack. Value range 0x41200000 (10 ms) to
|
||||
0x42c80000 (100 ms)
|
||||
04-09-03 = compressor release. Value range 0x41200000 (10 ms) to
|
||||
0x44fa0000 (2 s)
|
||||
05-09-03 = compressor trim. Value range 0xc0c00000 (-6 dB) to
|
||||
0x00000000 (0 dB)
|
||||
02-0a-03 = leveler makeup gain. Value range 0x00000000 to 0x42c80000.
|
||||
03-0a-03 = leveler gain reduction. Value range 0x00000000 to 0x42c80000.
|
||||
|
||||
Channel index values (mm in the above tables) are as follows on the 828 Mk3.
|
||||
|
||||
0x02 = mic 1
|
||||
0x03 = mic 2
|
||||
0x04 - 0x0b = analog 1-8
|
||||
0x0c - 0x0d = SPDIF 1 and 2
|
||||
0x0e - 0x15 = ADAT A 1-8
|
||||
0x16 - 0x1c = ADAT B 1-8
|
||||
|
||||
If a channel pair is flagged as a stereo pair then only the first control
|
||||
register is written to.
|
||||
|
||||
Reverb parameters:
|
||||
02-00-04 = predelay. 0x00000000 (0 ms) to 0x42c80000 (100 ms).
|
||||
03-00-04 = shelf filter frequency. 0x447a0000 (1 kHz) to 0x469c4000 (20
|
||||
kHz).
|
||||
04-00-04 = shelf filter cut. 0xc2200000 (-40 dB) to 0x00000000 (0 dB).
|
||||
05-00-04 = reverb time. 0x42c80000 (100 ms) to 0x476a6000 (60 sec).
|
||||
06-00-04 = reverb design: low time. 0x00000000 (0%) to 0x42c80000 (100%).
|
||||
07-00-04 = reverb design: mid time. 0x00000000 (0%) to 0x42c80000 (100%).
|
||||
08-00-04 = reverb design: high time. 0x00000000 (0%) to 0x42c80000
|
||||
(100%).
|
||||
09-00-04 = reverb design: crossover low. 0x42c80000 (100 Hz) to
|
||||
0x469c4004 (20 kHz).
|
||||
0a-00-04 = reverb design: crossover high. 0x447a0000 (1 kHz) to
|
||||
0x469c4004 (20 kHz).
|
||||
0b-00-04 = reverb design: width. 0xbf800000 (-100%) to 0x3f800000
|
||||
(+100%).
|
||||
0d-00-04 = early reflections size. 0x42480000 (50%) to 0x43c64000 (400%).
|
||||
0e-00-04 = early reflections level. 0x00000000 (-inf) to 0x3f800000 (0
|
||||
dB).
|
||||
|
||||
|
||||
CuemixFX switches
|
||||
-----------------
|
||||
|
||||
Switches and discrete controls in CuemixFX are controlled through a
|
||||
2-quadlet write to the CuemixFX register. The format of this is
|
||||
|
||||
02 aa 69 v1 - bb k1 k2 k3
|
||||
|
||||
where:
|
||||
aa = packet serial number
|
||||
bb = bus/channel index (0x00 = mix bus 1 or mic 1, depending on the control)
|
||||
v1 = the value of the switch / discrete control
|
||||
k1-k2-k3 = the key of the control being set
|
||||
|
||||
Depending on the control, the channel number being set is communicated
|
||||
either as part of the key (for controls which operate on a per-mixbus basis)
|
||||
or in the "bb" field of the packet (for controls which operate on a
|
||||
per-input/output basis.
|
||||
|
||||
The keys appear to be rather structured. The value of k3 appears to
|
||||
indicate what kind of object the key applies to:
|
||||
|
||||
00 = global resource (eg: talkback)
|
||||
01 = input channel (corresponding to a physical device input)
|
||||
02 = a channel in a bus mix
|
||||
03 = output channel (corresponding to a physical device output)
|
||||
04 = global configuration
|
||||
|
||||
Keys presently identified:
|
||||
00-00-01 = Input channel phase. Value is 0x00 (normal), 0x01 (invert)
|
||||
bb is the input channel index (0 is mic 1). When two adjacent
|
||||
channels are paired the phase of each can still be independently
|
||||
controlled. FIXME: also under the 00-cc-01 entry.
|
||||
00-00-02 = bus output assignment. Values are:
|
||||
0xff = disabled
|
||||
0x00 = main L-R
|
||||
0x01-0x04 = Analog 1-2 though 7-8
|
||||
0x05 = SPDIF 1-2
|
||||
0x06 = Phones L-R
|
||||
0x07-0x0a = ADAT A 1-2 through 7-8
|
||||
0x0b-0x0e = ADAT B 1-2 through 7-8
|
||||
00-03-00 = talkback channel select. The value is the 0-based channel index
|
||||
of the talkback channel.
|
||||
00-cc-01 = input channel EQ/dynamics switches. Value is 0x00 (off) or 0x01
|
||||
(on). cc values identified to date:
|
||||
00 = phase (0x00 normal, 0x01 invert)
|
||||
02 = EQ F enable
|
||||
03 = EQ A enable
|
||||
04 = EQ C enable
|
||||
05 = EQ D enable
|
||||
06 = EQ E enable
|
||||
07 = EQ B enable
|
||||
08 = EQ G enable
|
||||
0a = Compressor enable
|
||||
0b = Leveler enable
|
||||
FIXME: work out some way to identify the EQs.
|
||||
00-cc-03 = output channel EQ/dynamics switches. Value is 0x00 (off) or
|
||||
0x01 (on). cc values identified to date:
|
||||
01 = EQ F enable
|
||||
02 = EQ A enable
|
||||
03 = EQ C enable
|
||||
04 = EQ D enable
|
||||
05 = EQ E enable
|
||||
06 = EQ B enable
|
||||
07 = EQ G enable
|
||||
09 = Compressor enable
|
||||
0a = Leveler enable
|
||||
00-04-00 = talkback listen channel select. The value is the 0-based
|
||||
channel index of the talkback listen channel.
|
||||
00-mm-02 = mix channel mute. mm is the channel index as for other keys.
|
||||
Value is 0x00 (off) or 0x01 (on).
|
||||
00-01-02 = bus mute. Values are 0x00 (off), 0x01 (on).
|
||||
00-0c-03 = output channel monitor enable (0x00=off, 0x01=on)
|
||||
01-00-01 = input channel mono/stereo mode. Value is 0x00 (mono), 0x01
|
||||
(stereo). bb (bus select byte) is always zero for this key
|
||||
since this acts globally on the input.
|
||||
01-00-04 = Reverb split point. Value is 0x00 for "mixes", 0x01 for
|
||||
"outputs".
|
||||
01-mm-02 = mix channel solo. mm is as for the mute control. Value is
|
||||
0x00 (off) or 0x01 (on).
|
||||
01-0a-03 = output channel leveler mode (0x00=compress, 0x01=limit)
|
||||
01-0c-03 = output channel talkback talk (0x00=off, 0x01=on)
|
||||
02-0c-03 = output channel talkback listen (0x00=off, 0x01=on)
|
||||
03-00-01 = input channel swap L and R. Value is 0x00 (no swap), 0x01
|
||||
(swap). bb is the input channel index.
|
||||
04-00-01 = input channel stereo mode. Value is 0x00 for normal stereo,
|
||||
0x01 for MS. Relevant only if input channel is in stereo mode
|
||||
(and thus part of a stereo pair).
|
||||
06-00-01 = input channel Vlimit on (mic channels only). Values are 0x00
|
||||
(off), 0x01 (on).
|
||||
06-0a-01 = input channel compressor mode (0x00=peak, 0x01=RMS)
|
||||
06-0b-01 = input channel leveler mode (0x00=compress, 0x01=limit)
|
||||
06-09-03 = output channel compressor mode (0x00=peak, 0x01=RMS)
|
||||
07-00-01 = input channel Vlimit lookahead (mic channels only). Values are
|
||||
0x00 (off), 0x01 (on).
|
||||
08-00-01 = input channel soft clip (mic channels only). Values are 0x00
|
||||
(off), 0x01 (on).
|
||||
0c-00-04 = Reverb early reflections model. Value is 0x00-0x04 for "Room
|
||||
A" through to "Room E". bb is zero.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,942 @@
|
|||
RME Fireface-400 / Fireface-800 register map
|
||||
============================================
|
||||
|
||||
Version: 0.26
|
||||
Author: Jonathan Woithe
|
||||
Date: 11 April 2013
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
CBA = Command Buffer Address
|
||||
FF800 = Fireface-800
|
||||
FF400 = Fireface-400
|
||||
|
||||
Multi-byte values sent to/from the Fireface in async packets are generally
|
||||
little endian - that is, the device interprets quadlets in asynchronous
|
||||
packets as little endian even though the bus definition is big-endian. If
|
||||
writing a driver for use on a little endian machine, this means that a lack
|
||||
of byte swapping (to account for the bus endianness standard) will cause bit
|
||||
0 on the host to be bit 0 on the device.
|
||||
|
||||
By default, FFADO however adheres to the bus standards and byteswaps on
|
||||
little endian machines. Under this regime, bit 0 on the host will in fact
|
||||
be read by the device as the least significant bit in the most significant
|
||||
byte.
|
||||
|
||||
In order to retain consistency with device documentation, the FFADO RME
|
||||
driver currently sends async packet data in the little endian format which
|
||||
the RME device expects. Although this is technically wrong (in so far as
|
||||
the FireWire standard is concerned), at this stage it is considered that
|
||||
introducing an endianness difference between the FFADO driver and the
|
||||
documentation is likely to result in maintenance issues down the track.
|
||||
|
||||
The bit maps in this document regarding the configuration registers are
|
||||
written from the device's point of view. That is, the values quoted should
|
||||
be sent to the device in little endian format unless otherwise stated.
|
||||
|
||||
Curiously enough, preliminary investigations suggest that audio data appears
|
||||
to be sent on the bus in big endian format (although this is to be
|
||||
confirmed).
|
||||
|
||||
The FF800 includes a number of instrument options for input 1 which are
|
||||
described using several different terms interchangeably:
|
||||
- "Drive" (also referred to as "fuzz") activates 25 dB extra gain
|
||||
- "Speaker emulation" (also referred to as "filter") removes LF noise and
|
||||
some HF
|
||||
- "Limiter" activates a soft-limiter with a threshold of -10 dBFS. This
|
||||
can only be switched off if the Front input is used for channel 1.
|
||||
|
||||
|
||||
Device address space location
|
||||
-----------------------------
|
||||
|
||||
While some register addresses are common between the two interfaces, the
|
||||
absolute addresses of the settings and control differ. These are defined
|
||||
relative to the device "command buffer" address:
|
||||
|
||||
FF800: command buffer address (CBA) = 0xfc88f000
|
||||
FF400: command buffer address (CBA) = 0x80100500
|
||||
|
||||
The location of the configuration (settings) registers relative to the
|
||||
command buffer is consistent across devices:
|
||||
|
||||
conf reg 1 address = command buffer address + 5*4
|
||||
|
||||
For a FF800 this equates to 0xfc88f014.
|
||||
|
||||
|
||||
Controlling sample rate (DDS)
|
||||
-----------------------------
|
||||
|
||||
Sample rate is controlled by writing the desired sample rate in Hz to the
|
||||
sample rate control register located at offset 0 from the command buffer
|
||||
address (0xfc88f000 on a FF800). The hardware DDS allows a wide range of
|
||||
frequencies to be requested (possibly anything from 30 kHz up to 210 kHz).
|
||||
The more common rates are of course 32k, 44.1k, 48k, the pull-up/down rates
|
||||
(44.056k, 44.144k, 45.937k, 46.080k, 47.952k, 48.048k) and the corresponding
|
||||
2x and 4x rates.
|
||||
|
||||
Software connecting to the Fireface device is restricted to the normal rates
|
||||
of 32k, 44.1k, 48k and the related 2x and 4x rates.
|
||||
|
||||
If the device is in master clock mode and the user has not made an explicit
|
||||
DDS setting, the hardware DDS will be determined by the sampling rate
|
||||
requested by the application opening the device. If a DDS frequency has
|
||||
been requested by the user the actual rate used by the device will be that
|
||||
DDS frequency regardless of what the application has asked for. In this
|
||||
case a device open will only succeed if the software has requested a speed
|
||||
whose multiplier matches the DDS configuration.
|
||||
|
||||
If the device is locked to an external clock, a device open will succeed
|
||||
only if the multiplier of the requested sampling rate matches that of the
|
||||
external rate.
|
||||
|
||||
The device status registers allow the PC to determine the sampling rate when
|
||||
an external clock is in use. However, there is no way to read the sampling
|
||||
rate when in master clock mode. It is therefore necessary to cache this in
|
||||
the driver so it can be provided when requested.
|
||||
|
||||
In terms of multipliers the RME treats sample rates greater than 112000 Hz
|
||||
as 4x rates, with rates greater than 56000 Hz as 2x rates. Rates less than
|
||||
30000 Hz and greater than 210000 Hz are invalid.
|
||||
|
||||
|
||||
Configuration registers 1, 2 and 3
|
||||
----------------------------------
|
||||
|
||||
Most RME device configuration is done using configuration registers 1, 2
|
||||
and 3. For the ff800 these are:
|
||||
|
||||
config1 = configuration register 1 (FF800: 0xfc88f014, FF400: 0x80100514)
|
||||
config2 = configuration register 2 (FF800: 0xfc88f018, FF400: 0x80100518)
|
||||
config3 = configuration register 3 (FF800: 0xfc88f01c, FF400: 0x8010051c)
|
||||
|
||||
In essence the configuration registers start at CBA+5*4 for both interfaces.
|
||||
|
||||
When making a configuration change these registers are always written in a
|
||||
block of 12 bytes starting at 0xfc88f014 with a block write operation.
|
||||
|
||||
Configuration register 1 (FF800: 0xfc88f014, FF400: 0x80100514):
|
||||
|
||||
bits 31-18: unknown, set to 0
|
||||
bits 17-16: Phones level:
|
||||
00 = +4 dBu
|
||||
01 = -10 dBV
|
||||
10 = hi-gain
|
||||
bits 15-13: unknown, set to 0
|
||||
bits 12-10: Output level control (part 1 of 2: FPGA LED drive):
|
||||
001 = hi-gain
|
||||
010 = +4dBU
|
||||
100 = -10dBV
|
||||
bit 9: FF800: Instr option: Drive (part 1 of 2: FPGA LED drive) (active = 1)
|
||||
FF400: Channel 3 "instrument" switch
|
||||
bit 8: FF800: Phantom power, mic 10 (active = 1)
|
||||
FF400: Channel 3 "pad" switch
|
||||
bit 7: Phantom power, mic 8 (active = 1)
|
||||
bit 6: unknown, set to 0
|
||||
bits 5-3: Input level control (part 1 of 2: FPGA LED drive):
|
||||
001 = lo-gain
|
||||
010 = +4dBU
|
||||
100 = -10dbV
|
||||
bit 2: FF800: Instrument option: speaker emulation (aka "filter") (part 1
|
||||
of 2: FPGA LED drive) (active = 1)
|
||||
FF400: Channel 4 "instrument" switch
|
||||
bit 1: FF800: Phantom power, mic 9 (active = 1)
|
||||
FF400: Channel 4 "pad" switch
|
||||
bit 0: Phantom power, mic 7 (active = 1)
|
||||
|
||||
Configuration register 2 (FF800: 0xfc88f018, FF400: 0x80100518):
|
||||
|
||||
bits 31-12: unknown, set to 0
|
||||
bit 11: Input #1 front switch (active = 1)
|
||||
bit 10: unknown, set to 0
|
||||
bit 9: Instrument option: Drive (part 2 of 2: CPLD function) (active = 0)
|
||||
bit 8: Input #8 rear switch (active = 1)
|
||||
bit 7: Input #8 front switch (active = 1)
|
||||
bit 6: Input #7 rear switch (active = 1)
|
||||
bit 5: Input #7 front switch (active = 1)
|
||||
bits 4-3: Output level control (part 2 of 2: CPLD function):
|
||||
00 = undefined
|
||||
01 = -10dBV
|
||||
10 = hi-gain
|
||||
11 = +4dBU
|
||||
bit 2: Input #1 rear switch (active = 1)
|
||||
bits 1-0: Input level control (part 2 of 2: CPLD function):
|
||||
00 = lo-gain
|
||||
01 = undefined
|
||||
10 = +4dBU
|
||||
11 = -10dbV
|
||||
|
||||
Configuration register 3 (FF800: 0xfc88f01c, FF400: 0x8010051c):
|
||||
bit 31: "Drop and stop": always set to 1
|
||||
bit 30: Unit option: TMS (active = 1)
|
||||
bits 29-27: set to 0
|
||||
bit 26: set to 1 for FF400, 0 for FF800
|
||||
bits 25-17: set to 0
|
||||
bit 16: P12DB_AN0 (normally set to 0)
|
||||
bit 15: set to 0
|
||||
bit 14: Toggle TCO (normally set to 0)
|
||||
bit 13: Word clock single speed: 0 = off, 1 = on
|
||||
bits 12-10: Sync reference source:
|
||||
000 = ADAT1
|
||||
001 = ADAT2
|
||||
011 = SPDIF
|
||||
100 = Word clock
|
||||
101 = TCO
|
||||
bit 9: SPDIF input source: 0 = coax, 1 = ADAT2 port
|
||||
bit 8: SPDIF output option: ADAT2
|
||||
bit 7: SPDIF output option: non-audio
|
||||
bit 6: SPDIF output option: emphasis
|
||||
bit 5: SPDIF output option: professional
|
||||
bit 4: QS control (set to 1)
|
||||
bit 3: DS control (set to 1)
|
||||
bit 2: Freq1 control (set to 1)
|
||||
bit 1: Freq0 control (set to 1)
|
||||
bit 0: Clock mode: 0 = Master, 1 = Autosync
|
||||
|
||||
On the FF400, writing to these registers with valid values for the first
|
||||
time after power up has the side effect of extingishing the "Host" LED.
|
||||
|
||||
|
||||
Device status registers
|
||||
-----------------------
|
||||
|
||||
There are up to 4 read-only device status registers available, starting at
|
||||
address 0x801c0000. There seems to be a slight difference in the mapping of
|
||||
status register 0 depending on the size of the read. If only 2 registers
|
||||
(quadlets) are read the "general" layout is assumed. If on the other hand 4
|
||||
registers are used (used when determining the status of the device's
|
||||
streaming system) the layout of register 0 is slightly different.
|
||||
|
||||
Status register 0:
|
||||
bits 9-0: on a 2-quadlet read these bits are all zero
|
||||
bits 9-0: on a 4-quadlet read when in autosync mode, these bits contain
|
||||
SR/250, where SR is the sample rate to be passed to the
|
||||
streaming subsystem when starting streaming.
|
||||
bit 10: ADAT1 lock achieved
|
||||
bit 11: ADAT2 lock achieved
|
||||
bit 12: Device is synced to ADAT1
|
||||
bit 13: Device is synced to ADAT2
|
||||
bits 17-14: SPDIF frequency:
|
||||
0000 = undefined 0101 = 88.2k
|
||||
0001 = 32k 0110 = 96k
|
||||
0010 = 44.1k 0111 = 128k
|
||||
0011 = 48k 1000 = 176.4k
|
||||
0100 = 64k 1001 = 192k
|
||||
bit 18: Device is synced to SPDIF
|
||||
bit 19: Over detected
|
||||
bit 20: SPDIF lock achieved
|
||||
bit 21: undefined (read as zero)
|
||||
bits 24-22: Primary sync source:
|
||||
000 = ADAT1 100 = Word clock
|
||||
001 = ADAT2 101 = TCO
|
||||
011 = SPDIF
|
||||
bits 28-25: autosync (external) frequency (defined as for SPDIF frequency)
|
||||
bit 29: Device is synced to word clock
|
||||
bit 30: Word clock lock achieved
|
||||
bit 31: undefined (read as zero)
|
||||
|
||||
Status register 1:
|
||||
bit 0: master clock mode active
|
||||
bits 21-1: undefined
|
||||
bit 22: Device is synced to TCO
|
||||
bit 23: TCO lock achieved
|
||||
bits 31-24: undefined
|
||||
|
||||
Status register 2:
|
||||
bits 31-0: (FF800 only) FireWire iso channel used for data from FF800 to PC
|
||||
|
||||
Status register 3:
|
||||
bits 31-0: unused
|
||||
|
||||
|
||||
Interfacing to device flash
|
||||
---------------------------
|
||||
|
||||
To preserve the device's settings across power cycles the settings are
|
||||
stored in a flash memory on the device. This is read during driver
|
||||
initialisation to ensure the driver's status agrees with that of the device.
|
||||
|
||||
There are several classes of things stored in flash: operational settings,
|
||||
volumes (ie: the mixer status) and configuration/firmware. Device settings
|
||||
start at address 0x3000f0000 on the FF800 and 0x00060000 on the FF400; mixer
|
||||
data starts at 0x3000e0000 on the FF800 and 0x00070000 on the
|
||||
FF400.
|
||||
|
||||
|
||||
Reading blocks from the flash (flash command 0x2)
|
||||
|
||||
For the FF800 the entire buffer is read directly from flash as a single
|
||||
block if the block is less than a sector (256 bytes, 64 quadlets). Polling
|
||||
for "device not busy" should commence after a wait of 5 ms. For anything
|
||||
larger, writes are split into sector-sized sub-blocks.
|
||||
|
||||
For the FF400, the buffer is read in 32-quadlet sub-blocks. A partial block
|
||||
is read at the end if the total buffer size is not a multiple of
|
||||
32-quadlets. To read a sub-block, the address is placed in register
|
||||
0x80100288 and the sub-block size (in bytes) in 0x8010028c. A 0x02 is
|
||||
then written to CBA+(8*4) to initiate the read. Polling for "device not
|
||||
busy" should commence after a wait of 2 ms. Once not busy the data is
|
||||
available for reading from 0x80100290.
|
||||
|
||||
|
||||
Writing blocks to the flash (flash command 1)
|
||||
|
||||
For the FF800, the buffer is written to flash in 256-byte (64 quadlet)
|
||||
sectors. Polling for "device not busy" should commence after a wait of 5
|
||||
ms. A write request for a length less than a sector will be honoured by the
|
||||
device (this is done when writing device settings).
|
||||
|
||||
For the FF400, the buffer is written in 32-quadlet (128-byte) sub-blocks via
|
||||
a bounce buffer. If the final sub-block is not 32-quadlets the write is
|
||||
only as big as the sub-block (that is, no padding takes place). The
|
||||
sub-block data to be written is sent to the block starting at 0x80100290.
|
||||
The 2-quadlet register at 0x80100288 is set with the flash address to write
|
||||
the block to and the size (in bytes) of the data block. Finally, a 0x1 is
|
||||
written to CBA+(8*4) to initiate the write. Polling for "device not busy"
|
||||
should commence after a wait of 2 ms.
|
||||
|
||||
|
||||
Getting other data from flash
|
||||
|
||||
There are a few other commands issued to the flash memory system for
|
||||
obtaining data about the connected interface:
|
||||
|
||||
* Device revision
|
||||
|
||||
On the FF800 this is read directly from register 0x200000100.
|
||||
|
||||
On the FF400, 0xf is written to CBA+(8*4). Poll for "not busy" after a
|
||||
wait of 2ms. Once not busy the revision is read from register
|
||||
0x80100290.
|
||||
|
||||
|
||||
Erasing the flash
|
||||
|
||||
The flash is divided into sections and it is possible to erase each section
|
||||
separately. Therefore one only has to erase section of interest when
|
||||
changing something.
|
||||
|
||||
On the FF400, erasure is controlled by writing a special magic number to
|
||||
the the flash control register (CBA+8*4):
|
||||
Erase volume: write 0xe
|
||||
Erase settings: write 0xd
|
||||
Erase configuration (firmware): write 0xc
|
||||
|
||||
On the FF800, erasing is controlled by writing 0 to the applicable register:
|
||||
Erase volume: register is 0x3fffffff4
|
||||
Erase settings: register is 0x3fffffff0
|
||||
Erase firmware: register is 0x3fffffff8
|
||||
Erase configuration: register is 0x3fffffffc
|
||||
|
||||
It's not clear what the distinction between "configuration" and "firmware"
|
||||
is. The FF400 appears to only support "configuration" but treats this as
|
||||
"firmware". The FF800 supports both as distinct options.
|
||||
|
||||
After issuing the erase command one should wait for 500 ms before polling
|
||||
the device for the "not busy" status.
|
||||
|
||||
|
||||
Waiting for flash
|
||||
|
||||
When interacting with the device's flash memory one must wait for the
|
||||
completion of an operation before attempting another. The location of the
|
||||
"device busy" flag differs between the FF400 and FF800.
|
||||
|
||||
On the FF800 is part of the quadlet register at 0x801c0004 (part of the
|
||||
read-only status register block beginning at 0x801c0000). The device is
|
||||
ready to accept another command when bit 30 is set.
|
||||
|
||||
On the FF400 the wait state is found by reading a quadlet from CBA+8*4.
|
||||
If this quadlet is zero the FF400 is ready to accept another command.
|
||||
|
||||
Most device flash operations have a minimum time to complete. There's no
|
||||
point in polling the device busy flag until at least this much time has
|
||||
elapsed.
|
||||
|
||||
|
||||
Device settings format
|
||||
----------------------
|
||||
|
||||
The device settings are stored in flash as an array of 59 32-bit unsigned
|
||||
integers. These are:
|
||||
0 - Device ID (FF400=0x77e1f4ea)
|
||||
1 - Device revision (FF400=0x004af3d8)
|
||||
2 - ASIO latency (FF400=0x00000001)
|
||||
3 - Samples per frame (FF400 default is 0x30)
|
||||
4 SPDIF input mode (1=coax, 0=optical)
|
||||
5 SPDIF output emphasis active
|
||||
6 SPDIF output is "professional" (ie: AES/EBU)
|
||||
7 Clock mode (0=master, 1=autosync)
|
||||
8 SPDIF output is non-audio (eg: AC3 passthrough)
|
||||
9 Sync reference
|
||||
10 SPDIF output mode (0=coax only, 1=coax+optical)
|
||||
11 - Check input
|
||||
12 - Status (FF400 idle=0x77e691d0)
|
||||
13 - Register[4] (FF400 = 0x004adbc8,0x001377c0,0x000301ee,0x00000001)
|
||||
17 - Iso receive channel (FF400=0x7ffde000)
|
||||
18 - Iso transmit channel (FF400=0x77f43664)
|
||||
19 - Timecode (FF400 example: 0x004b35c8)
|
||||
20 - Device type (FF400=0x00000001)
|
||||
21 - Number of devices (FF400=0x77f43664)
|
||||
22 TMS (FF400=0x00000000)
|
||||
23 - Speed (FF400=0x00000000)
|
||||
24 - Channels available (high) (FF400=0x0012f2e4)
|
||||
25 - Channels available (low) (FF400=0x00000000)
|
||||
26 Limit bandwidth setting (0=all channels on, 1=no adat2, 2=analog+spdif
|
||||
only, 3=analog only)
|
||||
27 - Bandwidth allocated (FF400=0x00000000)
|
||||
28 Stop on dropout (FF400=0x00000000)
|
||||
29 Input level (0=lo-gain, 2=+4dBU, 1=-10dBV)
|
||||
30 Output level (2=hi-gain, 1=+4dBU, 0=-10dBV)
|
||||
31 Mic level [0] - FF400: Phoneslevel-1
|
||||
FF800: Channel 7 front/rear select (0=rear, 1=front,
|
||||
2=front+rear)
|
||||
32 Mic level [1] - FF400: unused
|
||||
FF800: Channel 8 front/rear select (0=rear, 1=front,
|
||||
2=front+rear)
|
||||
33 Mic phantom power [4]
|
||||
37 Instrument - FF400: unused
|
||||
FF800: Channel 1 front/rear selector (0=rear, 1=front,
|
||||
2=front+rear)
|
||||
38 Filter (aka speaker emulation)
|
||||
39 Fuzz (aka drive)
|
||||
40 - Sync align
|
||||
41 - Device index (FF400=0x77e24d0d)
|
||||
42 - Advanced dialog (FF400=0x000201f8) [but might be related to TCO control)
|
||||
43 Sample rate (eg: 0x0000ac44) [set to 0x00000000 unless DDS enabled]
|
||||
44 - Interleaved (FF400=0x00000000)
|
||||
45 - Sn (FF400=0x77e14925)
|
||||
46 Word clock single speed (1=single speed)
|
||||
47 - Number of channels (FF400=0x000000f0)
|
||||
48 - Dropped samples
|
||||
49 p12db_an[0] - Disable limiter, settable only if channel 1 front jack active
|
||||
50 - p12db_an[1-9]
|
||||
|
||||
"-" = elements not used (under MacOSX at least)
|
||||
|
||||
Total size: 59 quadlets
|
||||
|
||||
The default state of these quadlets is 0xffffffff, which is taken to
|
||||
indicate that the respective setting has not been written to flash. This in
|
||||
turn causes the driver to assume its own default value. While these
|
||||
settings can be changed in real time by writing to the relevant control
|
||||
registers, these are not persistent across device power cycles. To make
|
||||
them persistent it is necessary to store them into the flash.
|
||||
|
||||
|
||||
Flash mixer settings layout
|
||||
---------------------------
|
||||
|
||||
Mixer (volume) data starts at 0x3000e0000 on the FF800 and 0x00070000 on the
|
||||
FF400. There are several control groups in the mixer:
|
||||
0xe0000 (FF800): "mixer shadow", FF800 only
|
||||
0xe2000 (FF800) / 0x70000 (FF400), 0x0800 bytes: 16-bit volume array
|
||||
0xe2800 (FF800) / 0x70800 (FF400), 0x0800 bytes: 16-bit pan array
|
||||
0xe3000 (FF800) / 0x71000 (FF400), 0x0040 bytes: 16-bit "vol3" array +
|
||||
"enable MIDI control" + "submix" + zero padding to 64 quadlets
|
||||
|
||||
All group allocations are written in their entirety (that is, 0x0800 bytes),
|
||||
with zero padding on the end as needed. Each write is grouped in sectors,
|
||||
with each sector being 256 bytes (64 quadlets).
|
||||
|
||||
It is not known why the "mixer shadow" is stored in the case of the FF800.
|
||||
It comprises a copy of the 32-bit matrix mixer settings (see "Fireface-800
|
||||
mixer controls" below), and the information is essentially a duplicate of
|
||||
what's in the "volume" and "pan" arrays. In any case, what's done is done.
|
||||
The "mixer shadow" values are written in 64-quadlet (256-byte) blocks, one
|
||||
per hardware output channel. The FF800 has 28 hardware input channels (I)
|
||||
and 28 software playback channels (P). Each output has a 64-quadlet block
|
||||
formatted as follows:
|
||||
|
||||
Faders for physical inputs 1..I, zero pad to 32-quadlet boundary
|
||||
Faders for software playbacks 1..P, zero pad to 32-quadlet boundary
|
||||
|
||||
There are 28 hardware input/output channels on the FF800 and 18 for the
|
||||
FF400.
|
||||
|
||||
The "volume" and "pan" arrays are arranged in blocks of N (32 for FF800, 18
|
||||
for FF400) 16-bit elements. Each block contains the volume/pan value for
|
||||
each of N possible physical inputs or playbacks when sent to one of the N/2
|
||||
physical stereo output pairs. Elements are ordered in the standard Fireface
|
||||
channel index order. The arrangement of the blocks are as follows:
|
||||
|
||||
Inputs 1..N to output pair 1+2
|
||||
Playbacks 1..N to output pair 1+2
|
||||
Inputs 1..N to output pair 3+4
|
||||
Playbacks 1..N to output pair 3+4
|
||||
:
|
||||
Inputs 1..N to output pair N/2-1 and N/2
|
||||
Playbacks 1..N to output pair N/2-1 and N/2
|
||||
|
||||
In the case of the FF800, N (32) is greater than the number of physical
|
||||
inputs and mono outputs available (28). Array elements corresponding to
|
||||
non-existent inputs, outputs or playbacks are filled with zeros.
|
||||
|
||||
The "vol3" array represents the hardware output volume settings. The 16-bit
|
||||
volume data for each of the hardware output channels is included in the
|
||||
standard Fireface channel index order. The array has room for 30 outputs
|
||||
while the FF400/FF800 has only 18/28 outputs; elements corresponding to
|
||||
outputs not physically present are set to zero. In addition, a boolean
|
||||
indicating whether MIDI control is enabled is stored in zero-based array
|
||||
index 30 while a submix index is stored in array index 31 (array elements
|
||||
are considered 16-bit here). The meaning of the submix index isn't known;
|
||||
it's thought that the GUI mixer applications in other systems use this as a
|
||||
convenient place to store the submix index that the user was last editting
|
||||
(assuming they were editting in submix mode).
|
||||
|
||||
All 16-bit values are written in little endian byte order.
|
||||
|
||||
The "volume" and "vol3" values are unsigned 16-bit values:
|
||||
0x0000 = -inf (minimum)
|
||||
0x0255 = -6 dB
|
||||
0x0323 = 0 dB
|
||||
0x03ff = 6 dB (maximum)
|
||||
|
||||
When panned hard left or right, the value F written to the flash as a
|
||||
channel's volume given a fader value of V (0..0x10000) appears to be:
|
||||
|
||||
F = (1023.0/3) * ln( V*(exp(3)-1)/65536 + 1)
|
||||
|
||||
F is rounded to the nearest integer value.
|
||||
|
||||
The "pan" values are unsigned 16-bit values. 0x0000 is hard left, 0x0080 is
|
||||
centre and 0x0100 is hard right. Therefore if the pan value is represented
|
||||
as a floating point number Pf from 0.0 (hard left) to 1.0 (hard right), the
|
||||
pan value Pv written to flash will be
|
||||
|
||||
Pv = 0x0100 * Pf
|
||||
|
||||
In the hardware, each channel of a stereo pair is controlled independently
|
||||
the mixer registers. It is therefore necessary to convert bidirectionally
|
||||
between fader value pairs and the volume/pan pair as used in the flash. Let
|
||||
V0 and V1 be the fader value (0..0x10000) for each of the two channels. The
|
||||
volume (V) and pan (P) values can be calculated as follows.
|
||||
|
||||
V = V0 + V1
|
||||
|
||||
Pf = V1 / (V0 + V1)
|
||||
|
||||
P = 0x0100 * Pf
|
||||
|
||||
V is then transformed into the equivalent flash value F according to
|
||||
the expression given previously:
|
||||
|
||||
F = (1023.0/3) * ln( V*(exp(3)-1)/65536 + 1)
|
||||
|
||||
When starting with the volume/pan pair, V is first calculated from F by
|
||||
rearranging the above equation. Pf is then calculated:
|
||||
|
||||
Pf = P / 0x100
|
||||
|
||||
This allows V0 and V1 to be found:
|
||||
|
||||
V0 = V * (1 - Pf)
|
||||
|
||||
V1 = V * Pf
|
||||
|
||||
Careful attention to round-off is required to ensure that flash and fader
|
||||
values remain unchanged through fader-flash-fader and flash-fader-flash
|
||||
round trips.
|
||||
|
||||
User interfaces under other operating systems include a "pan law" control
|
||||
which sets the gain when panned to centre. This setting is not sent to the
|
||||
device at any time; the default in the mixer software is -6 dB. Other
|
||||
options are -4.5 dB, -3 dB and 0 dB. Changing these affects the values sent
|
||||
to the individual mixer registers (and hense the "mixer shadow"), but not
|
||||
the values stored in the "volume" and "pan" flash arrays. In the case of
|
||||
the FF400, the power on state obtained from flash is therefore independent
|
||||
of the pan law control (the FF800 stores the mixer shadow data and could
|
||||
make use of it if it wanted to). Experimentation shows that when powering
|
||||
up, the FF400 assumes a pan law of -6 dB when mapping from the volume/pan
|
||||
flash arrays to individual mixer element registers. Tests are still to be
|
||||
done on the FF800 to see if it uses the "mixer shadow" values instead of the
|
||||
volume/pan arrays.
|
||||
|
||||
|
||||
TCO (TimeCode Option)
|
||||
---------------------
|
||||
|
||||
The TCO is an optional card for the FF800 which adds video timecode
|
||||
generation and clock locking capabilities to the FF800. It is controlled by
|
||||
writing a block of 4 quadlets to register 0x810f0020 while its status can be
|
||||
retrieved by reading a block of 4 quadlets from register 0x801f0000.
|
||||
|
||||
The configuration space is as follows.
|
||||
|
||||
Quadlet 0 (written to register 0x810f0020):
|
||||
bit 31: MTC active if set to 1
|
||||
bits 30-0: reserved (equal zero)
|
||||
|
||||
Quadlet 1 (written to register 0x810f0024):
|
||||
bits 31-12: reserved (equal to zero)
|
||||
bits 11-10: LTC format (00=24fps, 01=25fps, 10=29.97fps, 11=30fps)
|
||||
bit 9: dropframe active
|
||||
bit 8: set timecode request
|
||||
bit 7: reserved (set to 0)
|
||||
bit 6: PAL format video input
|
||||
bit 5: NTSC format video input
|
||||
bit 4-3: reserved (set to 0)
|
||||
bits 2-1: word clock input rate (00=1x, 01=2x, 10=4x)
|
||||
bit 0: reserved (set to 0)
|
||||
|
||||
Quadlet 2 (written to register 0x810f0028):
|
||||
bit 31: set sampling frequency from application
|
||||
bits 30-29: input select (00=wordclock, 01=video, 10=LTC)
|
||||
bit 28: input termination active
|
||||
bit 27: Base frequency (0=44.1 kHz, 1=48 kHz)
|
||||
bit 26: Pull up flag
|
||||
bit 25: Pull down flag
|
||||
bit 24: Pull up/down amount (0=0.1%, 1=4.0%)
|
||||
bit 23: reserved (set to 0)
|
||||
bit 22: Flywheel select
|
||||
bit 21: Jam sync select
|
||||
bits 20-19: dropframes select (unused, set to 0)
|
||||
bits 18-17: word clock conversion (00=1:1, 01=44.1->48, 10=48->44.1)
|
||||
bit 16: set TC run
|
||||
bits 15-0: reserved, set to 0.
|
||||
|
||||
Quadlet 3:
|
||||
bits 31-0: reserved, set to 0
|
||||
|
||||
The 4 quadlets returned by a TCO status query are mapped as follows.
|
||||
|
||||
Quadlet 0:
|
||||
bit 31: set to 1
|
||||
bits 30-24: LTC, hours field in BCD(*)
|
||||
bit 23: set to 1
|
||||
bits 22-16: LTC, minutes field in BCD
|
||||
bit 15: set to 1
|
||||
bits 14-8: LTC, seconds field in BCD
|
||||
bit 7: set to 1
|
||||
bits 6-0: LTC, frames field in BCD
|
||||
|
||||
Quadlet 1:
|
||||
bit 31: set to 1
|
||||
bits 30-24: reserved (equal to zero)
|
||||
bit 23: set to 1
|
||||
bits 22-16: reserved (equal to zero)
|
||||
bit 15: set to 1
|
||||
bits 14-12: reserved (equal to zero)
|
||||
bits 11-10: LTC format (00=24fps, 01=25fps, 10=29.97fps, 11=30fps)
|
||||
bit 9: dropframe active
|
||||
bit 8: reserved (read as zeros)
|
||||
bit 7: set to 1
|
||||
bit 6: PAL format video input
|
||||
bit 5: NTSC format video input
|
||||
bit 4: Word clock input valid (0=invalid, 1=valid)
|
||||
bit 3: LTC input valid (0=invalid, 1=valid)
|
||||
bits 2-1: reserved (read as zeros)
|
||||
bit 0: TCO lock flag (0=no lock, 1=locked)
|
||||
|
||||
Quadlet 2
|
||||
bit 31: set to 1
|
||||
bits 30-24: reserved (equal to zero)
|
||||
bit 23: set to 1
|
||||
bits 22-16: reserved (equal to zero)
|
||||
bit 15: set to 1
|
||||
bits 14-8: upper 7 bits of PLL phase
|
||||
bit 7: set to 1
|
||||
bits 6-0: the lower 7 bits of the PLL phase
|
||||
|
||||
Quadlet 3:
|
||||
bit 31: set to 1
|
||||
bits 30-16: reserved
|
||||
bit 15: set to 1
|
||||
bits 14-0: set to 0
|
||||
|
||||
Notes:
|
||||
(*) BCD is Binary Coded Decimal. The high nibble (which is only 3 bits in
|
||||
these cases) contains the "tens" digit while the lower nibble contains
|
||||
the "units" digit.
|
||||
|
||||
The calculation of the PLL phase from quadlet 2 (q2) is as follows:
|
||||
|
||||
phase = (q2 & 0x7f) + ((q2 & 0x7f00) >> 1)
|
||||
|
||||
which then allows the incoming frequency to be calculated using
|
||||
|
||||
freq = (25000000 * 16) / phase
|
||||
|
||||
To detect the presence of a TCO in a FF800, read the 4 TCO status quadlets.
|
||||
If a TCO is present:
|
||||
- bits 31, 23, 15 and 7 in quadlets 0, 1 and 2 will be 1, AND
|
||||
- bits 31 and 15 in quadlet 3 will be 1, AND
|
||||
- bits 14 to 0 in quadlet 3 will be 0
|
||||
|
||||
|
||||
Streaming control registers
|
||||
---------------------------
|
||||
|
||||
There appears to be a number of registers involved in the setup of device
|
||||
streaming.
|
||||
|
||||
Device (streaming) initialisation register (FF800: 0x20000001c, FF400: CBA)
|
||||
|
||||
This register comprises the 3 quadlets starting at address 0x20000001c on
|
||||
the FF800 and the 5 quadlets starting at the CBA on the FF400. The first
|
||||
quadlet contains the sample rate in Hz. The second quadlet is mapped as
|
||||
follows:
|
||||
bits 31-11 = number of audio channels
|
||||
bits 10-0 = iso tx channel (PC to interface)
|
||||
In all local tests with a FF800 the value of this quadlet was always equal
|
||||
to 0x0000e000 (28 channels, PC transmits on iso channel 0).
|
||||
|
||||
The third quadlet is mapped as follows.
|
||||
bits 10-0 = number of audio channels
|
||||
bit 11 = speed flag; set to 1 if FireWire bus is at 800 Mbps
|
||||
In local tests with a FF800 the value of this register was always 0x0000001c
|
||||
(28 channels, 400 Mbps FireWire bus).
|
||||
|
||||
The forth and fifth quadlets (used only by the FF400) are zero.
|
||||
|
||||
After this register is configured, 4 quadlets are read starting from
|
||||
0x801c0000. When read, these are the device status registers.
|
||||
|
||||
Device (streaming) start register (FF800: 0x200000028, FF400: CBA+0x0c):
|
||||
|
||||
The start of streaming differs between the FF400 and FF800 in more than just
|
||||
the address of the relevant register. On the FF800 this register is mapped
|
||||
as follows:
|
||||
bits 10-0 = number of audio channels
|
||||
bit 11 = bus speed flag; set to 1 if FireWire bus is at 800 Mbps
|
||||
On a FF400 the register is as follows:
|
||||
bits 4-0 = number of audio channels
|
||||
bits 9-5 = iso tx channel (PC to interface)
|
||||
During initial testing with a FF800 the value of this register was always
|
||||
0x0000001c (28 audio channels, PC tx on iso channel 0).
|
||||
|
||||
Channel mute setup register (write to 0x801c0000):
|
||||
|
||||
After writing to the streaming start register, 0x70 bytes (28 quadlets) are
|
||||
written starting at 0x801c0000. Each quadlet represents one channel on the
|
||||
Fireface800. A value of 1 mutes the respective channel - indeed on closing
|
||||
down streaming each quadlet is set to 1. During startup some values are set
|
||||
to zero - the ones set to zero may be determined by the channels which have
|
||||
active software data sources although this is yet to be confirmed with more
|
||||
testing. Irrespective of the setting of these registers it appears that
|
||||
data for all channels is always sent to/from the Fireface-800.
|
||||
|
||||
Note that when register 0x801c0000 is read it functions as the device status
|
||||
register. It is read during streaming setup, but obviously it bears no
|
||||
relationship to the channel mute status.
|
||||
|
||||
Streaming end register (FF800: 0x200000034, FF400: CBA+0x4):
|
||||
|
||||
On the FF800, streaming is stopped by writing 3 zeroed quadlets to
|
||||
consecutive registers starting at address 0x200000034. For the FF400 one
|
||||
writes 3 zeroed quadlets to consecutive registers from CBA+0x4, followed
|
||||
by a 0x00000001 to CBA+0x10 (making a 4-quadlet write in total).
|
||||
|
||||
|
||||
Iso data
|
||||
--------
|
||||
|
||||
Audio/midi data is sent and received on isochronous channels previously
|
||||
configured by the driver. On a dedicated bus with nothing else present, the
|
||||
stream to the fireface is sent on iso channel 0 while data from the fireface
|
||||
is sent on iso channel 1.
|
||||
|
||||
No CIP header is included in the iso data packet. Fireface data follows
|
||||
immediately after the standard 2-quadlet FireWire iso packet header.
|
||||
|
||||
Each iso packet contains a number of samples across all 28 device channels
|
||||
(18 channels in the case of the ff400). For 1x rates, 7 samples per channel
|
||||
seem to be sent. Thus the size of the data portion of a 1x iso packet is
|
||||
28*4*7 = 784, with a total packet size being 784 + 8 = 792.
|
||||
|
||||
The data is sent with one audio channel per quadlet. The audio data is a 24
|
||||
bit integer stored in the most-significant 3 bytes of a quadlet. The LSB
|
||||
(low byte) of certain channels in the stream sent by the Fireface is used to
|
||||
send synchronising information:
|
||||
|
||||
Low byte of channel 6 = current frame
|
||||
Low byte of channel 7 = phase
|
||||
Low byte of channel 1 = rx sample counter, low byte
|
||||
Low byte of channel 4 = rx sample counter, high byte
|
||||
Low byte of channel 0 = tx buffer size, low byte
|
||||
Low byte of channel 5 = tx buffer size, high byte
|
||||
Low byte of channel 2 & 3 = unknown (midi?)
|
||||
|
||||
The low byte data from channels 0-7 is repeated in channels 8-15 and 16-23
|
||||
respectively, with channels 24-27 containing the low byte data from channels
|
||||
0-3. This repetition holds for the low bytes of channels 2-3 in all data
|
||||
seen so far, it might not necessarily be the case in general - it depends
|
||||
what the low byte data from channels 2 and 3 are used for.
|
||||
|
||||
The rx sample counter appears to be used to detect missed samples. The
|
||||
current frame and phase from a received packet is used in conjunction with
|
||||
the stored values of these from the previous frame to track the phase of
|
||||
the audio clock.
|
||||
|
||||
A "frame" consists of a fixed number of samples across all channels of the
|
||||
device. At 1x rates this appears to be 7, but it might not be fixed. Even
|
||||
though this is the same as the number of samples per channel per packet, a
|
||||
given packet can experience a change in the "current frame" part way
|
||||
through. In other words, the "current frame" is not necessarily constant
|
||||
for all samples in a packet.
|
||||
|
||||
With the number of samples per channel contained in each iso packet it is
|
||||
not necessary for the RME to send audio data in every iso cycle. When it is
|
||||
deemed that a cycle can be skipped the RME simply doesn't send any packet at
|
||||
all in that cycle. This contrasts with other devices which tend to send
|
||||
empty "placeholder" packets when the need arises. This means that a cycle
|
||||
without a packet from the RME is not necessarily an error condition. To
|
||||
detect dropped packets one must instead rely on the rx sample counter
|
||||
embedded in the audio data stream.
|
||||
|
||||
|
||||
Input preamp / output amp gain control
|
||||
--------------------------------------
|
||||
|
||||
On the Fireface-400 the gain of the mic/instrument preamps and output
|
||||
amplifiers can be set. Mic channel gain is in steps of 1 dB from 10 dB up to
|
||||
65 dB, with 0dB also available. Instrument input gain ranges from 0 dB to
|
||||
18 dB in 0.5 dB steps. Output gains range from +6 dB down to -53 dB (a 58
|
||||
dB range) in steps of 1 dB, with compete "mute" also available.
|
||||
|
||||
The gains are set using the register at 0x801c0180.
|
||||
|
||||
bits 31-24: unknown (set to 0)
|
||||
bits 23-16: channel being set (see below)
|
||||
bits 15-8: unknown (set to 0)
|
||||
bits 7-0: the gain value
|
||||
|
||||
For mic channels the gain value is the dB value. For instrument channels, a
|
||||
value of 2G is written for a gain value of G (thereby allowing a stepsize of
|
||||
0.5 dB). For output gain, 0 = +6 dB, 0x3b = -53 dB, 0x3f = mute.
|
||||
|
||||
The definition of the "channel being set" is as follows.
|
||||
0 = mic input 1 gain
|
||||
1 = mic input 2 gain
|
||||
2 = instrument input 3 gain
|
||||
3 = instrument input 4 gain
|
||||
4-9 = analog outputs 1-6 level
|
||||
10-11 = phones output level
|
||||
12-13 = SPDIF output level
|
||||
14-21 = ADAT outputs 1-8 level
|
||||
|
||||
|
||||
Firefice-400 mixer controls
|
||||
---------------------------
|
||||
|
||||
The Fireface-400 matrix mixer is controlled using a block of registers
|
||||
starting at 0x80080000. An 18x18 matrix mixer is implemented allowing any
|
||||
hardware input to be sent to any device output. Pan control is effected by
|
||||
manipulating the "left/right" controls within an output pair.
|
||||
|
||||
For each input channel block the order of channels is Analog 1-8, SPDIF 1-2,
|
||||
ADAT 1-8.
|
||||
|
||||
0x80080000 - 0x80080044: input channel sends to Analog 1 output.
|
||||
0x80080048 - 0x8008008c: playback channel sends to Analog 1 output.
|
||||
0x80080090 - 0x800800d4: input channel sends to Analog 2 output.
|
||||
0x800800d8 - 0x8008011c: playback channel sends to Analog 2 output.
|
||||
:
|
||||
0x80080990 - 0x800809d4: input channel sends to ADAT 8 output.
|
||||
0x800809d8 - 0x80080a1c: playback channel sends to ADAT 8 output.
|
||||
|
||||
0x80080f80: matrix mixer analog 1 output fader
|
||||
0x80080f84: matrix mixer analog 2 output fader
|
||||
:
|
||||
0x80080fc4: matrix mixer ADAT 8 output fader
|
||||
|
||||
Each fader control ranges from 0x00000000 (-inf) through 0x00008000 (0.0 dB)
|
||||
up to a maximum of 0x00010000 (+6.0 dB). -52.7 dB appears to correspond to
|
||||
a value of 0x0000004c, -46.6 dB is 0x00000099. From this we can see that if
|
||||
v is the value being written, the dB gain applied can be found using
|
||||
|
||||
dB = 20.log10(v/32768)
|
||||
|
||||
Alternatively, to set the gain to G dB, one calculates the value to send to
|
||||
the device (v) using
|
||||
|
||||
v = 32768 * exp10(G/20)
|
||||
|
||||
When setting the output fader controls, the associated output amplifier
|
||||
gain control (see previous section) are generally kept in sync. That is, if
|
||||
register 0x80080f80 (analog 1 output fader) is set to 0 dB, so is the analog
|
||||
output 1 level via register 0x801c0180.
|
||||
|
||||
|
||||
Fireface-800 mixer controls
|
||||
---------------------------
|
||||
|
||||
The matrix mixer on the Fireface-800 is controlled using a block of
|
||||
registers starting at 0x80080000. A 28x28 matrix mixer is implemented
|
||||
allowing any device input to be sent to any device output. The pan controls
|
||||
are synthesised by manipulating the "left/right" controls.
|
||||
|
||||
In each sub-block, the order of channels is in fireface numeric order. That
|
||||
is, Analog 1-10, SPDIF, ADAT1 1-8, ADAT2 1-8.
|
||||
|
||||
0x80080000 - 0x8008006c: input channel sends to Analog 1 output.
|
||||
0x80080080 - 0x800800ec: playback channel sends to Analog 1 output.
|
||||
0x80080100 - 0x8008016c: input channel sends to Analog 2 output.
|
||||
0x80080180 - 0x800801ec: playback channel sends to Analog 2 output.
|
||||
:
|
||||
0x80081b00 - 0x80081b6c: input channel sends to ADAT2-8 output.
|
||||
0x80081b80 - 0x80081bec: playback channel sends to ADAT2-8 output.
|
||||
|
||||
0x80081f80: matrix mixer analog 1 output fader
|
||||
0x80081f84: matrix mixer analog 2 output fader
|
||||
:
|
||||
0x80081fec: maxtrix mixer ADAT2-8 output fader
|
||||
|
||||
Each fader control ranges from 0x00000000 (-inf) through 0x00008000 (0.0 dB)
|
||||
and up to a maximum setting of 0x00010000 (+6.0 dB). As for the
|
||||
Fireface-400, if v is the value being written, the dB gain applied can be
|
||||
found using
|
||||
|
||||
dB = 20.log(v/32768)
|
||||
|
||||
Mute is synthesised by setting the respective send value to -inf (0).
|
||||
Conversely, solo is synthesised by muting all sends to the selected bus
|
||||
except the send being soloed.
|
||||
|
||||
Note that a different scale is used when writing mixer settings into flash.
|
||||
Refer to the "Flash mixer settings layout" section for further details.
|
||||
|
||||
|
||||
Metering values
|
||||
---------------
|
||||
|
||||
The Fireface-800 appears to provide hardware support for metering. The RME
|
||||
mixer application periodically sends block read requests for register
|
||||
0x80100000 with a size of 0x3f8. What is returned is a set of two
|
||||
datablocks with data in little-endian (least significant bit/word first)
|
||||
format. The first block contains arrays of 64-bit floating point numbers
|
||||
representing channel amplitude with decay, presumedly useful for metering
|
||||
display. Arrays are:
|
||||
|
||||
28-element array for input channel amplitude with decay
|
||||
28-element array for playback amplitudes with decay (educated guess)
|
||||
28-element array for output amplitudes with decay
|
||||
|
||||
The second data block contains signed 32 bit integers representing the input
|
||||
amplitudes without decay. Valid range is 0 - 0x7ffffff. Again there are 3
|
||||
arrays:
|
||||
|
||||
28-element array for input channel ampltude
|
||||
28-element array for playback amplitudes (educated guess)
|
||||
28-element array for output amplitudes
|
||||
|
||||
At the end of this second block are two zero quadlets. Their purpose is
|
||||
unknown at this stage.
|
||||
|
||||
In each 28-element array the channel data appears in standard fireface
|
||||
order.
|
||||
|
||||
|
||||
Host LED
|
||||
--------
|
||||
|
||||
The "host" LED of the FF800 is controlled by a dedicated register at
|
||||
0x200000324. Note that this register address goes beyond the 32-bit
|
||||
boundary.
|
||||
|
||||
On the FF400 the host LED is controlled internally. On power up it is
|
||||
turned on. Once the host PC programs the configuration registers with
|
||||
valid values the host LED will automatically turn off.
|
|
@ -0,0 +1,411 @@
|
|||
RME Fireface800 protocol notes
|
||||
==============================
|
||||
|
||||
Author: Jonathan Woithe
|
||||
Date: 24 March 2008
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This document contains random notes made while observing the protocol used
|
||||
by the RME Fireface 800 interface. This document is not necessarily all
|
||||
that coherent but fully documents what is seen on the bus when various
|
||||
actions are carried out. For a distilled version of our current knowledge
|
||||
of the protocol please refer to rme_config_register_map.txt.
|
||||
|
||||
The information contained here was observed from a Fireface 800 device:
|
||||
RME vendor ID: 0x000a35
|
||||
GUID: 0x0093e1daf1
|
||||
Node capabilities: 0x0083c0
|
||||
Unit spec ID: 0x0a35
|
||||
Sw version number: 0x0001
|
||||
Model ID: 0x101800
|
||||
|
||||
|
||||
Setting device configuration options in general
|
||||
-----------------------------------------------
|
||||
|
||||
It seems that generally device configuration is effected by writing 0x0c
|
||||
bytes to register 0xfc88f014. However, the existing drivers do much
|
||||
more than just this. For example, when setting DDS inactive (which doesn't
|
||||
appear significantly different to setting it active):
|
||||
|
||||
Read 0x10 @ 0x801c0000: 01c000b1 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read @ 0xfffff000040c: 0xa3500
|
||||
Write 0xfc88f000: 0000ac44
|
||||
Read 0x10 @ 0x801c0000: 01c000b1 80001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b1 80001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 80001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 80001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b1 80001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
|
||||
When setting to 48k:
|
||||
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b0 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000b1 a0001001 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read @ 0xfffff000040c: 0xa3500
|
||||
Write 0xfc88f000: 0000bb80
|
||||
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000bf a0001007 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000c0 80001007 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
Read 0x10 @ 0x801c0000: 01c000c0 a0001007 ffffffff ffffffff
|
||||
Read @ 0xfffff0000410: 0x93e1daf1
|
||||
|
||||
When using the "course" control, the frequency seems to be set by:
|
||||
Read quadlet @ 0xfffff000040c: 0xa3500
|
||||
Write @ 0xfc88f000
|
||||
|
||||
Each write to 0xfc88f000 seems to be preceeded by a read of 0xfffff000040c,
|
||||
resulting in a value of 0xa3500. Before and after this is a variable number
|
||||
of repeats of the sequence
|
||||
block read of 0x10 bytes (4 quadlets) at 0x801c0000
|
||||
quadlet read at 0xfffff0000410
|
||||
|
||||
These reads seem to be some kind of status check on the device. However,
|
||||
there doesn't seem to be any consistent pattern as to when the write is
|
||||
performed relative to changes in these registers, nor does the process
|
||||
terminate in response to a particular setting of these registers. It seems
|
||||
that most if not all parameter settings are done with this pattern of reads
|
||||
above and below the actual write which (presumedly) activates the respective
|
||||
change.
|
||||
|
||||
Looking for patterns, consider the settings of quadlets 0 and 1 in the last block
|
||||
from 0x801c0000 before the respective set operation finishes:
|
||||
|
||||
32k: 01c00080 80001003
|
||||
44.056: 01c000b1 a0001001
|
||||
44.144: 01c000b0 80001001
|
||||
44.1: 01c000b1 80001001
|
||||
45.937: 01c000b8 a0001001
|
||||
46.080: 01c000b8 80001007
|
||||
47.952: 01c000c0 a0001007
|
||||
48: 01c000c0 a0001007
|
||||
48.048: 01c000c0 a0001007
|
||||
|
||||
mult 2x-1x:
|
||||
t=866835 01c0017f 8000100f
|
||||
876846 01c00180 8000100f
|
||||
377579 01c00180 8000100f
|
||||
t=512691 write
|
||||
t=868285 01c000c0 80001007
|
||||
878299 01c000c0 80001007
|
||||
379027 01c000c0 80001007
|
||||
|
||||
mult 2x-4x:
|
||||
t=278863 01c00180 a000100f
|
||||
769567 01c00180 a000100f
|
||||
779580 01c00180 a000100f
|
||||
280315 01c00180 a000100f
|
||||
t=536803 write
|
||||
t=771004 01c002ff a0001017
|
||||
781034 01c00300 a0001017
|
||||
281784 01c00300 a0001017
|
||||
|
||||
mult 4x-1x:
|
||||
t=784082 01c00300 a0001017
|
||||
794099 01c00300 a0001017
|
||||
294837 01c00300 a0001017
|
||||
t=753719 write
|
||||
t=785530 01c000c0 a0001007
|
||||
795553 01c000c0 a0001007
|
||||
296297 01c000c0 a0001007
|
||||
786993 01c000c0 a0001007
|
||||
797001 01c000c0 a0001007
|
||||
|
||||
mult 4x-2x:
|
||||
01c00300 80001017
|
||||
01c00300 80001017
|
||||
write
|
||||
01c00180 8000100f
|
||||
01c00180 a000100f
|
||||
01c00180 a000100f
|
||||
01c00180 a000100f
|
||||
|
||||
DDS active:
|
||||
01c000b1 a0001001
|
||||
01c000b1 a0001001
|
||||
01c000b0 a0001001
|
||||
write
|
||||
01c000b0 a0001001
|
||||
01c000b0 80001001
|
||||
01c000b1 a0001001
|
||||
01c000b0 80001001
|
||||
01c000b1 80001001
|
||||
01c000b1 80001001
|
||||
|
||||
DDS inactive:
|
||||
01c000b1 a0001001
|
||||
01c000b0 a0001001
|
||||
01c000b0 a0001001
|
||||
write
|
||||
01c000b1 80001001
|
||||
01c000b1 80001001
|
||||
01c000b0 80001001
|
||||
01c000b0 80001001
|
||||
01c000b1 80001001
|
||||
|
||||
Before and after settings:
|
||||
x - 32k: - 01c00080 80001003
|
||||
32-44.1: 01c00080 80001003 - 01c000b1 80001001
|
||||
44.1-48: 01c000b0 a0001001 - 01c000c0 a0001007
|
||||
48-96: 01c000c0 a0001007 - 01c00180 8000100f
|
||||
48-192: 01c000c0 a0001007 - 01c00300 80001017
|
||||
96-192: 01c00180 a000100f - 01c00300 a0001017
|
||||
|
||||
96-48: 01c00180 8000100f - 01c000c0 80001007
|
||||
192-48: 01c00300 a0001017 - 01c000c0 a0001007
|
||||
192-96: 01c00300 80001017 - 01c00180 a000100f
|
||||
|
||||
(jitter in bit 0 of 1st quadlet, and possibly bit 29 of 2nd quadlet)
|
||||
|
||||
For now there's little we can do - we'll ignore these additional reads (or
|
||||
maybe just do a few token ones of our own) and see how far we get. It seems
|
||||
that some clock rate information is included in here, but not the complete
|
||||
picture. Perhaps the base rate is available here, but little else. In fact
|
||||
there doesn't appear to be anywhere which conveys the device's rate back to
|
||||
the PC; the PC seemingly sets the rate to its desired rate and then
|
||||
effectively caches the sample rate.
|
||||
|
||||
|
||||
Buffer sizes
|
||||
------------
|
||||
All settings: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
It seems that device configuration is not affected by this setting.
|
||||
Obviously *some* setting is sent to the device whenever the buffer size is
|
||||
changed though.
|
||||
|
||||
|
||||
Clock mode
|
||||
----------
|
||||
Master: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
Autosync: 0xfc88f014 = 00000810 0000035e c400101e
|
||||
|
||||
|
||||
DDS (Frequency setting)
|
||||
-----------------------
|
||||
|
||||
32k: 0xfc88f000 = 00007d00 (32000)
|
||||
44.056: 0xfc88f000 = 0000ac18 (44056)
|
||||
44.144: 0xfc88f000 = 0000ac70 (44144)
|
||||
44.1k: 0xfc88f000 = 0000ac44 (44100)
|
||||
45.937: 0xfc88f000 = 0000b371 (45937)
|
||||
46.080: 0xfc88f000 = 0000b400 (46080)
|
||||
47.952: 0xfc88f000 = 0000bb50 (47952)
|
||||
48k: 0xfc88f000 = 0000bb80 (48000)
|
||||
48.048: 0xfc88f000 = 0000bbb0 (48048)
|
||||
|
||||
Multiplier (base freq of 48k):
|
||||
|
||||
1-2: 0xfc88f000 = 00017700 (96000)
|
||||
2-1: 0xfc88f000 = 0000bb80 (48000)
|
||||
2-4: 0xfc88f000 = 0002ee00 (192000)
|
||||
1-4: 0xfc88f000 = 0002ee00 (192000)
|
||||
4-2: 0xfc88f000 = 00017700 (96000)
|
||||
4-1: 0xfc88f000 = 0000bb80 (48000)
|
||||
|
||||
Set DDS active: 0xfc88f000 = 0000ac44
|
||||
Set DDS inactive: 0xfc88f000 = 0000ac44
|
||||
|
||||
To set the RME Fireface800 frequency, write the actual frequency to register
|
||||
0xfc88f000.
|
||||
|
||||
Setting DDS active doesn't appear to make any changes to the actual
|
||||
hardware.
|
||||
|
||||
|
||||
Input level
|
||||
-----------
|
||||
+4dBU: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
-10dBV: 0xfc88f014 = 00000820 0000035f c400101f
|
||||
lo-gain: 0xfc88f014 = 00000808 0000035c c400101f
|
||||
|
||||
|
||||
Inputs
|
||||
------
|
||||
#1 set front: 0xfc88f014 = 00000810 00000b5a c400101f
|
||||
#1 set front+rear: 0xfc88f014 = 00000810 00000b5e c400101f
|
||||
#1 set rear: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
|
||||
#7 set front: 0xfc88f014 = 00010810 0000033e c400101f
|
||||
#7 set front+rear: 0xfc88f014 = 00020810 0000037e c400101f
|
||||
#7 set rear: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
|
||||
#8 set front: 0xfc88f014 = 00000810 000002de c400101f
|
||||
#8 set front+rear: 0xfc88f014 = 00000810 000003de c400101f
|
||||
#8 set rear: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
|
||||
|
||||
Instrument options
|
||||
------------------
|
||||
none-drive: 0xfc88f014 = 00000a10 0000015e c400101f
|
||||
none-lim: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
none-sp_emu: 0xfc88f014 = 00000814 0000035e c400101f
|
||||
*-none: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
|
||||
"Lim" would appear to be a software setting since the hardware setting
|
||||
for "lim" seems to be the same as for "none".
|
||||
|
||||
|
||||
Output level
|
||||
------------
|
||||
+4dBU: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
-10dBV: 0xfc88f014 = 00001010 0000034e c400101f
|
||||
hi-gain: 0xfc88f014 = 00000410 00000356 c400101f
|
||||
|
||||
|
||||
Phantom
|
||||
-------
|
||||
mic 7 on: 0xfc88f014 = 00000811 0000035e c400101f
|
||||
mic 8 on: 0xfc88f014 = 00000890 0000035e c400101f
|
||||
mic 9 on: 0xfc88f014 = 00000812 0000035e c400101f
|
||||
mic 10 on: 0xfc88f014 = 00000910 0000035e c400101f
|
||||
|
||||
|
||||
SPDIF in
|
||||
--------
|
||||
coax: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
ADAT2: 0xfc88f014 = 00000810 0000035e c400121f
|
||||
|
||||
|
||||
SPDIF out
|
||||
---------
|
||||
ADAT2: 0xfc88f014 = 00000810 0000035e c400111f
|
||||
emphasis: 0xfc88f014 = 00000810 0000035e c400105f
|
||||
non-audio: 0xfc88f014 = 00000810 0000035e c400109f
|
||||
professional: 0xfc88f014 = 00000810 0000035e c400103f
|
||||
|
||||
|
||||
Sync reference source
|
||||
---------------------
|
||||
ADAT1: 0xfc88f014 = 00000810 0000035e c400001f
|
||||
ADAT2: 0xfc88f014 = 00000810 0000035e c400041f
|
||||
SPDIF: 0xfc88f014 = 00000810 0000035e c4000c1f
|
||||
TCO: 0xfc88f014 = 00000810 0000035e c400141f
|
||||
Wordclock: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
|
||||
|
||||
Unit options
|
||||
------------
|
||||
Start with all options on. Turn each of separately:
|
||||
-checkinput: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
-interleaved: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
-syncalign: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
-tms: 0xfc88f014 = 00000810 0000035e 8400101f
|
||||
|
||||
This tends to indicate that TMS is the only "unit option" which affects
|
||||
the hardware. All the others would appear to be software features.
|
||||
|
||||
|
||||
Word clock
|
||||
----------
|
||||
Single speed on: 0xfc88f014 = 00000810 0000035e c400301f
|
||||
Single speed off: 0xfc88f014 = 00000810 0000035e c400101f
|
||||
|
||||
|
||||
Streaming start
|
||||
---------------
|
||||
Frequency was 44100 Hz.
|
||||
|
||||
Playback:
|
||||
|
||||
Read from 0xfffff000040c: 0xa3500
|
||||
Read from 0xfffff000040c: 0xa3500
|
||||
Write 0x0c bytes to 0x20000001c: 0000ac44 0000e000 0000001c
|
||||
Read 0x10 bytes from 0x801c0000: 81c000b0 80001001 00000001 00000001
|
||||
Write quadlet to 0x200000028: 0x1c000000
|
||||
Write 0x70 bytes to 0x801c0000:
|
||||
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
00000000 00000000 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
00000001 00000001 00000001 00000001
|
||||
|
||||
Recording:
|
||||
|
||||
Reads from 0x801c0000 and 0xfffff0000410 as for parameter setting.
|
||||
0x801c0000 = 81c000b0 80001001 00000001 00000001
|
||||
0xfffff0000410 = 0x93e1daf1
|
||||
Read from 0xfffff000040c: 0xa3500
|
||||
Read quadlet from 0x801c0000: 81c000b1
|
||||
Read from 0xfffff000040c: 0xa3500
|
||||
Read quadlet from 0x801c0000: 81c000b1
|
||||
Read from 0xfffff000040c: 0xa3500
|
||||
Read from 0xfffff000040c: 0xa3500
|
||||
Write 0x0c bytes to 0x20000001c: 0000ac44 0000e000 0000001c
|
||||
Read 0x10 bytes from 0x801c0000: 81c000b0 a0001001 00000001 00000001
|
||||
Write quadlet to 0x200000028: 0x1c000000
|
||||
Read 0x10 bytes from 0x801c0000: 81c000b0 80001001 00000001 00000001
|
||||
Read from 0xfffff0000410: 0x93e1daf1
|
||||
...
|
||||
|
||||
|
||||
Streaming end
|
||||
-------------
|
||||
Frequency was 44100 Hz.
|
||||
|
||||
Playback:
|
||||
|
||||
Write 0x0c bytes to 0x200000034: 00000000 00000000 00000000
|
||||
Write 0x70 bytes to 0x801c0000:
|
||||
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
|
||||
00000001 00000001 00000001 00000001
|
||||
Read quadlet from 0xfffff000040c: 0xa3500
|
||||
|
||||
Recording:
|
||||
|
||||
Reads from:
|
||||
0x801c0000 = 81c000b1 80001001 00000001 00000001
|
||||
0xfffff0000410 = 0x93e1daf1
|
||||
Write 0x0c bytes to 0x200000034: 00000000 00000000 00000000
|
||||
More reads from 0x801c0000 and 0xfffff0000410
|
||||
|
||||
|
||||
Streaming data format
|
||||
---------------------
|
||||
The PC functions as the IRM and thus provides the cycle timer. The packets
|
||||
do not contain an SPH. It is not clear how device synchronisation is done.
|
||||
|
||||
Channels are sent in Fireface numeric order: Analog 1-10, spdif, ADAT1 1-8,
|
||||
ADAT2 1-8 (a total of 28 channels).
|
||||
|
||||
Each sample is 32 bits, seemingly ordered least significant byte first.
|
||||
|
||||
By default iso channel 0 is for PC->Fireface800 data and channel 1 carries
|
||||
Fireface800->PC audio data.
|
||||
|
||||
In an example capture, packets carrying 6 frames were observed, reportedly
|
||||
at 44.1 kHz. Packets of varying lengths were observed (0x230, 0x2a0 from
|
||||
the PC, a constant 0x310 from the Fireface800). It is not known how the
|
||||
device maintains the correct flow of packets for the various odd-ball
|
||||
frequencies it supports. It appears that in certain iso cycles an iso
|
||||
packet is simply not sent in order to resync, but how either side knows when
|
||||
to do this is a mystery at present.
|
||||
|
||||
The quadlets in a packet normally used by a CIP header seem to correspond to
|
||||
analog1+2.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,5 @@
|
|||
Name: libffado
|
||||
Description: FFADO
|
||||
Version: $VERSION
|
||||
Libs: -L$LIBDIR -lffado
|
||||
Cflags: -I$INCLUDEDIR
|
|
@ -0,0 +1 @@
|
|||
ffado.h
|
|
@ -0,0 +1,68 @@
|
|||
SUBSYSTEM!="firewire", GOTO="ffado_end"
|
||||
|
||||
# TC GROUP A/S
|
||||
ATTR{vendor}=="0x000166", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Mark of the Unicorn, Inc. (aka MOTU)
|
||||
ATTR{vendor}=="0x0001f2", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Apogee Electronics Corp.
|
||||
ATTR{vendor}=="0x0003db", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Alesis Corporation
|
||||
ATTR{vendor}=="0x000595", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Bridgeco Co AG
|
||||
ATTR{vendor}=="0x0007f5", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Presonus Corporation
|
||||
ATTR{vendor}=="0x000a92", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# TerraTec Electronic GmbH
|
||||
ATTR{vendor}=="0x000aac", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# M-Audio
|
||||
ATTR{vendor}=="0x000d6c", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Ego Systems Inc.
|
||||
ATTR{vendor}=="0x000f1b", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Loud Technologies Inc.
|
||||
ATTR{vendor}=="0x000ff2", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Stanton Magnetics,inc.
|
||||
ATTR{vendor}=="0x001260", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Focusrite Audio Engineering Limited
|
||||
ATTR{vendor}=="0x00130e", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Echo Digital Audio Corporation
|
||||
ATTR{vendor}=="0x001486", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Phonic Corporation
|
||||
ATTR{vendor}=="0x001496", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# BEHRINGER Spezielle Studiotechnik GmbH
|
||||
ATTR{vendor}=="0x001564", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# FlexRadio Systems
|
||||
ATTR{vendor}=="0x001c2d", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Weiss Engineering Ltd.
|
||||
ATTR{vendor}=="0x001c6a", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# ROLAND DG CORPORATION
|
||||
ATTR{vendor}=="0x0040ab", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# DnR
|
||||
ATTR{vendor}=="0x000f64", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Avid (for Mbox 3 Pro)
|
||||
ATTR{vendor}=="0x00a07e", GROUP="audio", ENV{ID_FFAOD}="1"
|
||||
# Yamaha (for GO4x devices)
|
||||
ATTR{vendor}=="0x00a0de", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Lexicon (from Onix-FW810S)
|
||||
ATTR{vendor}=="0x000fd7", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Allen and Heath
|
||||
ATTR{vendor}=="0x0004c4", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Midas
|
||||
ATTR{vendor}=="0x10c73f", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
|
||||
# The devices below are by vendors who make other firewire devices in
|
||||
# addition to their audio interfaces. They need more specific rules to
|
||||
# ensure only audio interfaces are covered here.
|
||||
|
||||
# Tascam, a subsiduary of TEAC (the OUI is TEAC's)
|
||||
ATTR{vendor}=="0x00022e", ATTR{model}=="0x010067", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
|
||||
# The devices below abuse another Vendor's ID, and therefore we need more advanced rules for those.
|
||||
|
||||
# CME, Matrix K FW
|
||||
ATTR{vendor}=="0x00000a", ATTR{model}=="0x030000", ATTR{units}=="*0x00a02d:0x010001*", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# Mackie, Onyx FireWire
|
||||
ATTR{vendor}=="0x00000f", ATTR{model}=="0x01006?", ATTR{units}=="*0x00a02d:0x010001*", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
# RME
|
||||
ATTR{vendor}=="0x000a35", ATTR{units}=="0x000a35:0x00000[1234]", GROUP="audio", ENV{ID_FFADO}="1"
|
||||
|
||||
LABEL="ffado_end"
|
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import os.path
|
||||
|
||||
Import( 'env' )
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
env.ScanReplace( "ffado.h.in" )
|
||||
|
||||
env.Alias( 'install', env.Install( os.path.join(env['includedir'],"libffado"), "ffado.h" ) )
|
||||
|
||||
env.Alias( 'install', env.Install( env['udevdir'], "60-ffado.rules" ) )
|
|
@ -0,0 +1,530 @@
|
|||
/* ffado.h
|
||||
*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FFADO_H
|
||||
#define FFADO_H
|
||||
|
||||
#define FFADO_API_VERSION $FFADO_API_VERSION
|
||||
|
||||
#define FFADO_MAX_NAME_LEN 256
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FFADO_STREAMING_MAX_URL_LENGTH 2048
|
||||
|
||||
#define FFADO_IGNORE_CAPTURE (1<<0)
|
||||
#define FFADO_IGNORE_PLAYBACK (1<<1)
|
||||
|
||||
enum ffado_direction {
|
||||
FFADO_CAPTURE = 0,
|
||||
FFADO_PLAYBACK = 1,
|
||||
};
|
||||
|
||||
typedef struct ffado_handle* ffado_handle_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define WEAK_ATTRIBUTE weak_import
|
||||
#else
|
||||
#define WEAK_ATTRIBUTE __weak__
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define FFADO_WEAK_EXPORT __attribute__((WEAK_ATTRIBUTE))
|
||||
#else
|
||||
/* Add support for non-gcc platforms here */
|
||||
#endif
|
||||
|
||||
/* ABI stuff */
|
||||
const char*
|
||||
ffado_get_version();
|
||||
|
||||
int
|
||||
ffado_get_api_version();
|
||||
|
||||
/* various function */
|
||||
|
||||
/* The basic operation of the API is as follows:
|
||||
*
|
||||
* ffado_streaming_init()
|
||||
* ffado_streaming_start()
|
||||
* while(running) {
|
||||
* retval = ffado_streaming_wait();
|
||||
* if (retval == -1) {
|
||||
* ffado_streaming_reset();
|
||||
* continue;
|
||||
* }
|
||||
*
|
||||
* ffado_streaming_transfer_capture_buffers(dev);
|
||||
*
|
||||
* for(all channels) {
|
||||
* // For both audio and MIDI channels, captured data is available
|
||||
* // in the buffer previously set with a call to
|
||||
* // ffado_streaming_set_capture_stream_buffer(dev, channel, buffer)
|
||||
* switch (channel_type) {
|
||||
* case audio:
|
||||
* // Process incoming audio as needed
|
||||
* case midi:
|
||||
* // Process incoming MIDI data as needed
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* for(all channels) {
|
||||
* // For both audio and MIDI channels, data is written to buffers
|
||||
* // previously associated with the playback channel streams using
|
||||
* // ffado_streaming_set_playback_stream_buffer(dev, channel, buffer)
|
||||
* switch (channel_type) {
|
||||
* case audio:
|
||||
* // Set audio playback buffer contents
|
||||
* case midi:
|
||||
* // Set MIDI playback buffer contents
|
||||
* }
|
||||
* }
|
||||
* ffado_streaming_transfer_playback_buffers(dev);
|
||||
*
|
||||
* }
|
||||
* ffado_streaming_stop();
|
||||
* ffado_streaming_finish();
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct _ffado_device ffado_device_t;
|
||||
|
||||
/**
|
||||
* The sample format used by the ffado streaming API
|
||||
*/
|
||||
|
||||
typedef unsigned int ffado_sample_t; // FIXME
|
||||
typedef unsigned int ffado_nframes_t;
|
||||
|
||||
#define FFADO_MAX_SPECSTRING_LENGTH 256
|
||||
#define FFADO_MAX_SPECSTRINGS 64
|
||||
/**
|
||||
* This struct serves to define the devices that should be used by the library
|
||||
* device_spec_strings is an array of pointers that should contain nb_device_spec_strings
|
||||
* valid pointers to strings.
|
||||
*
|
||||
* The spec strings should be null terminated and can be no longer
|
||||
* than FFADO_MAX_SPECSTRINGS.
|
||||
*
|
||||
* nb_device_spec_strings < FFADO_MAX_SPECSTRING_LENGTH
|
||||
* nb_device_spec_strings >= 0
|
||||
*
|
||||
* If nb_device_spec_strings == 0, all busses are scanned for attached devices, and
|
||||
* all found devices that are supported are combined into one large pseudo-device. The
|
||||
* device order is defined by the GUID of the device. Devices with lower GUID's will
|
||||
* be the first ones.
|
||||
*
|
||||
* If multiple device specifications are present, the device order is defined as follows:
|
||||
* - device(s) that correspond to a spec string with a lower index will be added before
|
||||
* devices from higher indexes.
|
||||
* - if a spec string results in multiple devices, they are sorted by GUID unless the
|
||||
* spec format dictates otherwise.
|
||||
*
|
||||
* The actual meaning of the device specification should be one of the following:
|
||||
* - Format 1: "hw:x[,y[,z]]"
|
||||
* x = the FireWire bus to use ('port' in raw1394 terminology)
|
||||
* (mandatory)
|
||||
* y = the node id the device currently has (bus resets might change that, but FFADO
|
||||
* will track these changes and keep using the device specified on startup)
|
||||
* (optional)
|
||||
* z = the stream direction to use.
|
||||
* 0 => capture (record) channels only
|
||||
* 1 => playback channels only
|
||||
* other/unspecified => both playback and capture
|
||||
* (optional)
|
||||
*
|
||||
* - Format 2: the device alias as defined in the ffado config file (UNIMPLEMENTED)
|
||||
*/
|
||||
typedef struct ffado_device_info {
|
||||
unsigned int nb_device_spec_strings;
|
||||
char **device_spec_strings;
|
||||
|
||||
/* add some extra space to allow for future API extention
|
||||
w/o breaking binary compatibility */
|
||||
int32_t reserved[32];
|
||||
} ffado_device_info_t;
|
||||
|
||||
/**
|
||||
* Structure to pass the options to the ffado streaming code.
|
||||
*/
|
||||
typedef struct ffado_options {
|
||||
/* driver related setup */
|
||||
int32_t sample_rate; /*
|
||||
* you can specify a value here or -1 to autodetect
|
||||
*/
|
||||
|
||||
/* buffer setup */
|
||||
int32_t period_size; /* one period is the amount of frames that
|
||||
* has to be sent or received in order for
|
||||
* a period boundary to be signalled.
|
||||
* (unit: frames)
|
||||
*/
|
||||
int32_t nb_buffers; /* the size of the frame buffer (in periods) */
|
||||
|
||||
/* packetizer thread options */
|
||||
int32_t realtime;
|
||||
int32_t packetizer_priority;
|
||||
|
||||
/* verbosity */
|
||||
int32_t verbose;
|
||||
|
||||
/* slave mode */
|
||||
int32_t slave_mode;
|
||||
/* snoop mode */
|
||||
int32_t snoop_mode;
|
||||
|
||||
/* add some extra space to allow for future API extention
|
||||
w/o breaking binary compatibility */
|
||||
int32_t reserved[24];
|
||||
|
||||
} ffado_options_t;
|
||||
|
||||
/**
|
||||
* The types of streams supported by the API
|
||||
*
|
||||
* A ffado_audio type stream is a stream that consists of successive samples.
|
||||
* The format is a 24bit UINT in host byte order, aligned as the 24LSB's of the
|
||||
* 32bit UINT of the read/write buffer.
|
||||
* The wait operation looks at this type of streams only.
|
||||
*
|
||||
* A ffado_midi type stream is a stream of midi bytes. The bytes are 8bit UINT,
|
||||
* aligned as the first 8LSB's of the 32bit UINT of the read/write buffer.
|
||||
*
|
||||
* A ffado_control type stream is a stream that provides control information. The
|
||||
* format of this control information is undefined, and the stream should be ignored.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ffado_stream_type_invalid = -1,
|
||||
ffado_stream_type_unknown = 0,
|
||||
ffado_stream_type_audio = 1,
|
||||
ffado_stream_type_midi = 2,
|
||||
ffado_stream_type_control = 3,
|
||||
} ffado_streaming_stream_type;
|
||||
|
||||
/**
|
||||
*
|
||||
* Audio data types known to the API
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ffado_audio_datatype_error = -1,
|
||||
ffado_audio_datatype_int24 = 0,
|
||||
ffado_audio_datatype_float = 1,
|
||||
} ffado_streaming_audio_datatype;
|
||||
|
||||
/**
|
||||
*
|
||||
* Wait responses
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ffado_wait_shutdown = -3,
|
||||
ffado_wait_error = -2,
|
||||
ffado_wait_xrun = -1,
|
||||
ffado_wait_ok = 0,
|
||||
} ffado_wait_response;
|
||||
|
||||
/**
|
||||
* Initializes the streaming from/to a FFADO device. A FFADO device
|
||||
* is a virtual device composed of several BeBoB or compatible devices,
|
||||
* linked together in one sync domain.
|
||||
*
|
||||
* This prepares all IEEE1394 related stuff and sets up all buffering.
|
||||
* It elects a sync master if nescessary.
|
||||
*
|
||||
* @param device_info provides a way to specify the virtual device
|
||||
* @param options options regarding buffers, ieee1394 setup, ...
|
||||
*
|
||||
* @return Opaque device handle if successful. If this is NULL, the
|
||||
* init operation failed.
|
||||
*
|
||||
*/
|
||||
ffado_device_t *ffado_streaming_init(
|
||||
ffado_device_info_t device_info,
|
||||
ffado_options_t options);
|
||||
|
||||
/**
|
||||
* This permits the setting of the period size at some time after
|
||||
* initialisation. The primary use of this function is to support the
|
||||
* setbufsize functionality of JACK.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param period the new period size
|
||||
* @return 0 on success, non-zero if an error occurred
|
||||
*/
|
||||
int ffado_streaming_set_period_size(ffado_device_t *dev,
|
||||
unsigned int period) FFADO_WEAK_EXPORT;
|
||||
|
||||
/**
|
||||
* preparation should be done after setting all per-stream parameters
|
||||
* the way you want them. being buffer data type etc...
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @return
|
||||
*/
|
||||
int ffado_streaming_prepare(ffado_device_t *dev);
|
||||
|
||||
|
||||
/**
|
||||
* Finishes the FFADO streaming. Cleans up all internal data structures
|
||||
* and terminates connections.
|
||||
*
|
||||
* @param dev the ffado device to be closed.
|
||||
*/
|
||||
void ffado_streaming_finish(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Returns the amount of capture channels available
|
||||
*
|
||||
* @param dev the ffado device
|
||||
*
|
||||
* @return the number of capture streams present & active on the device.
|
||||
* can be 0. returns -1 upon error.
|
||||
*/
|
||||
int ffado_streaming_get_nb_capture_streams(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Returns the amount of playack channels available
|
||||
*
|
||||
* @param dev the ffado device
|
||||
*
|
||||
* @return the number of playback streams present & active on the device.
|
||||
* can be 0. returns -1 upon error.
|
||||
*/
|
||||
int ffado_streaming_get_nb_playback_streams(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Copies the capture channel name into the specified buffer
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param number the stream number
|
||||
* @param buffer the buffer to copy the name into. has to be allocated.
|
||||
* @param buffersize the size of the buffer
|
||||
*
|
||||
* @return the number of characters copied into the buffer
|
||||
*/
|
||||
int ffado_streaming_get_capture_stream_name(ffado_device_t *dev, int number, char* buffer, size_t buffersize);
|
||||
|
||||
/**
|
||||
* Copies the playback channel name into the specified buffer
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param number the stream number
|
||||
* @param buffer the buffer to copy the name into. has to be allocated.
|
||||
* @param buffersize the size of the buffer
|
||||
*
|
||||
* @return the number of characters copied into the buffer
|
||||
*/
|
||||
int ffado_streaming_get_playback_stream_name(ffado_device_t *dev, int number, char* buffer, size_t buffersize);
|
||||
|
||||
/**
|
||||
* Returns the type of a capture channel
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param number the stream number
|
||||
*
|
||||
* @return the channel type
|
||||
*/
|
||||
ffado_streaming_stream_type ffado_streaming_get_capture_stream_type(ffado_device_t *dev, int number);
|
||||
|
||||
/**
|
||||
* Returns the type of a playback channel
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param number the stream number
|
||||
*
|
||||
* @return the channel type
|
||||
*/
|
||||
ffado_streaming_stream_type ffado_streaming_get_playback_stream_type(ffado_device_t *dev, int number);
|
||||
/*
|
||||
*
|
||||
* Note: buffer handling will change in order to allow setting the sample type for *_read and *_write
|
||||
* and separately indicate if you want to use a user buffer or a managed buffer.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the decode buffer for the stream. This allows for zero-copy decoding.
|
||||
* The call to ffado_streaming_transfer_buffers will decode one period of the stream to
|
||||
* this buffer. Make sure it is large enough.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param number the stream number
|
||||
* @param buff a pointer to the sample buffer, make sure it is large enough
|
||||
* i.e. sizeof(your_sample_type)*period_size
|
||||
* @param t the type of the buffer. this determines sample type and the decode function used.
|
||||
*
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
|
||||
int ffado_streaming_set_capture_stream_buffer(ffado_device_t *dev, int number, char *buff);
|
||||
int ffado_streaming_capture_stream_onoff(ffado_device_t *dev, int number, int on);
|
||||
|
||||
/**
|
||||
* Sets the encode buffer for the stream. This allows for zero-copy encoding (directly to the events).
|
||||
* The call to ffado_streaming_transfer_buffers will encode one period of the stream from
|
||||
* this buffer to the event buffer.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @param number the stream number
|
||||
* @param buff a pointer to the sample buffer
|
||||
* @param t the type of the buffer. this determines sample type and the decode function used.
|
||||
*
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
int ffado_streaming_set_playback_stream_buffer(ffado_device_t *dev, int number, char *buff);
|
||||
int ffado_streaming_playback_stream_onoff(ffado_device_t *dev, int number, int on);
|
||||
|
||||
ffado_streaming_audio_datatype ffado_streaming_get_audio_datatype(ffado_device_t *dev);
|
||||
int ffado_streaming_set_audio_datatype(ffado_device_t *dev, ffado_streaming_audio_datatype t);
|
||||
|
||||
/**
|
||||
* preparation should be done after setting all per-stream parameters
|
||||
* the way you want them. being buffer data type etc...
|
||||
*
|
||||
* @param dev
|
||||
* @return
|
||||
*/
|
||||
|
||||
int ffado_streaming_prepare(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Starts the streaming operation. This initiates the connections to the FFADO devices and
|
||||
* starts the packet handling thread(s). This has to be called before any I/O can occur.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
*
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int ffado_streaming_start(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Stops the streaming operation. This closes the connections to the FFADO devices and
|
||||
* stops the packet handling thread(s).
|
||||
*
|
||||
* @param dev the ffado device
|
||||
*
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int ffado_streaming_stop(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Resets the streaming as if it was stopped and restarted. The difference is that the connections
|
||||
* are not nescessarily broken and restored.
|
||||
*
|
||||
* All buffers are reset in the initial state and all data in them is lost.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
*
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int ffado_streaming_reset(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Waits until there is at least one period of data available on all capture connections and
|
||||
* room for one period of data on all playback connections
|
||||
*
|
||||
* @param dev the ffado device
|
||||
*
|
||||
* @return The number of frames ready. -1 when a problem occurred.
|
||||
*/
|
||||
ffado_wait_response ffado_streaming_wait(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Transfer & decode the events from the packet buffer to the sample buffers
|
||||
*
|
||||
* This should be called after the wait call returns, before reading/writing the sample buffers
|
||||
* with ffado_streaming_[read|write].
|
||||
*
|
||||
* The purpose is to allow more precise timing information. ffado_streaming_wait returns as soon as the
|
||||
* period boundary is crossed, and can therefore be used to determine the time instant of this crossing (e.g. jack DLL).
|
||||
*
|
||||
* The actual decoding work is done in this function and can therefore be omitted in this timing calculation.
|
||||
* Note that you HAVE to call this function in order for the buffers not to overflow, and only call it when
|
||||
* ffado_streaming_wait doesn't indicate a buffer xrun (xrun handler resets buffer).
|
||||
*
|
||||
* If user supplied playback buffers are specified with ffado_streaming_set_playback_buffers
|
||||
* their contents should be valid before calling this function.
|
||||
* If user supplied capture buffers are specified with ffado_streaming_set_capture_buffers
|
||||
* their contents are updated in this function.
|
||||
*
|
||||
* Use either ffado_streaming_transfer_buffers to transfer all buffers at once, or use
|
||||
* ffado_streaming_transfer_playback_buffers and ffado_streaming_transfer_capture_buffers
|
||||
* to have more control. Don't use both.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @return -1 on error.
|
||||
*/
|
||||
|
||||
int ffado_streaming_transfer_buffers(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Transfer & encode the events from the sample buffers to the packet buffer
|
||||
*
|
||||
* This should be called after the wait call returns, after writing the sample buffers
|
||||
* with ffado_streaming_write.
|
||||
*
|
||||
* If user supplied playback buffers are specified with ffado_streaming_set_playback_buffers
|
||||
* their contents should be valid before calling this function.
|
||||
*
|
||||
* Use either ffado_streaming_transfer_buffers to transfer all buffers at once, or use
|
||||
* ffado_streaming_transfer_playback_buffers and ffado_streaming_transfer_capture_buffers
|
||||
* to have more control. Don't use both.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @return -1 on error.
|
||||
*/
|
||||
|
||||
int ffado_streaming_transfer_playback_buffers(ffado_device_t *dev);
|
||||
|
||||
/**
|
||||
* Transfer & decode the events from the packet buffer to the sample buffers
|
||||
*
|
||||
* This should be called after the wait call returns, before reading the sample buffers
|
||||
* with ffado_streaming_read.
|
||||
*
|
||||
* If user supplied capture buffers are specified with ffado_streaming_set_capture_buffers
|
||||
* their contents are updated in this function.
|
||||
*
|
||||
* Use either ffado_streaming_transfer_buffers to transfer all buffers at once, or use
|
||||
* ffado_streaming_transfer_playback_buffers and ffado_streaming_transfer_capture_buffers
|
||||
* to have more control. Don't use both.
|
||||
*
|
||||
* @param dev the ffado device
|
||||
* @return -1 on error.
|
||||
*/
|
||||
|
||||
int ffado_streaming_transfer_capture_buffers(ffado_device_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FFADO_STREAMING */
|
|
@ -0,0 +1,4 @@
|
|||
test-cyclecalc
|
||||
test-debugmodule
|
||||
test-dll
|
||||
test-unittests-util
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "DeviceStringParser.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "libieee1394/configrom.h"
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
IMPL_DEBUG_MODULE( DeviceStringParser, DeviceStringParser, DEBUG_LEVEL_NORMAL );
|
||||
|
||||
DeviceStringParser::DeviceString::DeviceString(DeviceStringParser& parent)
|
||||
: m_Parent(parent)
|
||||
, m_node( -1 )
|
||||
, m_port( -1 )
|
||||
, m_guid( 0 )
|
||||
, m_String("")
|
||||
, m_Type(eInvalid)
|
||||
, m_debugModule( parent.m_debugModule )
|
||||
{
|
||||
}
|
||||
|
||||
DeviceStringParser::DeviceString::~DeviceString()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::DeviceString::parse(std::string s)
|
||||
{
|
||||
m_String = s;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "parse: %s\n", s.c_str());
|
||||
std::string prefix = s.substr(0,3);
|
||||
|
||||
if(s.compare(0,3,"hw:")==0) {
|
||||
m_Type = eBusNode;
|
||||
std::string detail = s.substr(3);
|
||||
std::string::size_type comma_pos = detail.find_first_of(",");
|
||||
if(comma_pos == std::string::npos) {
|
||||
// node is unspecified
|
||||
m_node = -1;
|
||||
std::string port = detail;
|
||||
errno = 0;
|
||||
m_port = strtol(port.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
m_Type = eInvalid;
|
||||
m_port = -1;
|
||||
m_node = -1;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse port\n");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::string port = detail.substr(0, comma_pos);
|
||||
std::string node = detail.substr(comma_pos+1);
|
||||
errno = 0;
|
||||
m_port = strtol(port.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
m_Type = eInvalid;
|
||||
m_port = -1;
|
||||
m_node = -1;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse port\n");
|
||||
return false;
|
||||
}
|
||||
errno = 0;
|
||||
m_node = strtol(node.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
m_Type = eInvalid;
|
||||
m_port = -1;
|
||||
m_node = -1;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse node\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (s.compare(0,5,"guid:")==0) {
|
||||
std::string detail = s.substr(5);
|
||||
m_Type = eGUID;
|
||||
errno = 0;
|
||||
m_guid = strtoll(detail.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
m_Type = eInvalid;
|
||||
m_guid = 0;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "failed to parse guid\n");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
m_Type = eInvalid;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "invalid\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::DeviceString::isValidString(std::string s)
|
||||
{
|
||||
std::string prefix = s.substr(0,3);
|
||||
if(s.compare(0,3,"hw:")==0) {
|
||||
std::string detail = s.substr(3);
|
||||
std::string::size_type comma_pos = detail.find_first_of(",");
|
||||
if(comma_pos == std::string::npos) {
|
||||
std::string port = detail;
|
||||
errno = 0;
|
||||
strtol(port.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::string port = detail.substr(0, comma_pos);
|
||||
std::string node = detail.substr(comma_pos+1);
|
||||
errno = 0;
|
||||
strtol(port.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
return false;
|
||||
}
|
||||
errno = 0;
|
||||
strtol(node.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (s.compare(0,5,"guid:")==0) {
|
||||
std::string detail = s.substr(5);
|
||||
errno = 0;
|
||||
strtoll(detail.c_str(), NULL, 0);
|
||||
if(errno) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::DeviceString::match(ConfigRom& configRom)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "match %p (%s)\n", &configRom, configRom.getGuidString().c_str());
|
||||
bool match;
|
||||
switch(m_Type) {
|
||||
case eBusNode:
|
||||
if(m_port < 0) {
|
||||
debugWarning("Need at least a port spec\n");
|
||||
return false;
|
||||
}
|
||||
match = configRom.get1394Service().getPort() == m_port;
|
||||
if(m_node >= 0) {
|
||||
match &= ((configRom.getNodeId() & 0x3F) == m_node);
|
||||
}
|
||||
if(match) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "(eBusNode) device matches device string %s\n", m_String.c_str());
|
||||
}
|
||||
return match;
|
||||
case eGUID:
|
||||
//GUID should not be 0
|
||||
match = m_guid && (m_guid == configRom.getGuid());
|
||||
if(match) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "(eGUID) device matches device string %s\n", m_String.c_str());
|
||||
}
|
||||
return match;
|
||||
case eInvalid:
|
||||
default:
|
||||
debugError("invalid DeviceString type (%d)\n", m_Type);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::DeviceString::operator==(const DeviceString& x)
|
||||
{
|
||||
bool retval;
|
||||
switch(m_Type) {
|
||||
case eBusNode:
|
||||
retval = (m_port == x.m_port) && (m_node == x.m_node);
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "eBusNode %d,%d == %d,%d? %d\n",
|
||||
m_port, m_node, x.m_port, x.m_node, retval);
|
||||
return retval;
|
||||
case eGUID:
|
||||
retval = m_guid && (m_guid == x.m_guid);
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "eGUID 0x%016" PRIX64 " == 0x%016" PRIX64 "? %d\n",
|
||||
m_guid, x.m_guid, retval);
|
||||
return retval;
|
||||
case eInvalid:
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "eInvalid \n");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStringParser::DeviceString::show()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_INFO, "string: %s\n", m_String.c_str());
|
||||
switch(m_Type) {
|
||||
case eBusNode:
|
||||
debugOutput(DEBUG_LEVEL_INFO, "type: eBusNode\n");
|
||||
debugOutput(DEBUG_LEVEL_INFO, " Port: %d, Node: %d\n",
|
||||
m_port, m_node);
|
||||
break;
|
||||
case eGUID:
|
||||
debugOutput(DEBUG_LEVEL_INFO, "type: eGUID\n");
|
||||
debugOutput(DEBUG_LEVEL_INFO, " GUID: %016" PRIX64 "\n", m_guid);
|
||||
break;
|
||||
case eInvalid:
|
||||
default:
|
||||
debugOutput(DEBUG_LEVEL_INFO, "type: eInvalid\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
DeviceStringParser::DeviceStringParser()
|
||||
{}
|
||||
|
||||
DeviceStringParser::~DeviceStringParser()
|
||||
{
|
||||
while(m_DeviceStrings.size()) {
|
||||
DeviceString *tmp = m_DeviceStrings.at(0);
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "removing device string: %p\n", tmp);
|
||||
m_DeviceStrings.erase(m_DeviceStrings.begin());
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::parseString(std::string s)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "parse: %s\n", s.c_str());
|
||||
|
||||
std::string::size_type next_sep;
|
||||
std::string tmp = s;
|
||||
do {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, " left: %s\n", tmp.c_str());
|
||||
next_sep = tmp.find_first_of(";");
|
||||
std::string to_parse = tmp.substr(0, next_sep);
|
||||
DeviceString *d = new DeviceString(*this);
|
||||
if(d == NULL) {
|
||||
debugError("failed to allocate memory for device string\n");
|
||||
continue;
|
||||
}
|
||||
if(d->parse(to_parse)) {
|
||||
addDeviceString(d);
|
||||
} else {
|
||||
debugWarning("Failed to parse device substring: \"%s\"\n",
|
||||
to_parse.c_str());
|
||||
delete d;
|
||||
}
|
||||
tmp = tmp.substr(next_sep+1);
|
||||
} while(tmp.size() && next_sep != std::string::npos);
|
||||
|
||||
pruneDuplicates();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::isValidString(std::string s)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "isvalid? %s\n", s.c_str());
|
||||
return DeviceString::isValidString(s);
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::match(ConfigRom& c)
|
||||
{
|
||||
return matchPosition(c) != -1;
|
||||
}
|
||||
|
||||
int
|
||||
DeviceStringParser::matchPosition(ConfigRom& c)
|
||||
{
|
||||
int pos = 0;
|
||||
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
|
||||
it != m_DeviceStrings.end();
|
||||
++it )
|
||||
{
|
||||
if((*it)->match(c)) {
|
||||
return pos;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::addDeviceString(DeviceString *o)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "adding device string: %p\n", o);
|
||||
if (hasDeviceString(o)){
|
||||
return false;
|
||||
}
|
||||
m_DeviceStrings.push_back(o);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::removeDeviceString(DeviceString *o)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "removing device string: %p\n", o);
|
||||
int i=findDeviceString(o);
|
||||
if (i<0) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "not found\n");
|
||||
return false;
|
||||
} else {
|
||||
DeviceString *tmp = m_DeviceStrings.at(i);
|
||||
m_DeviceStrings.erase(m_DeviceStrings.begin()+i);
|
||||
delete tmp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStringParser::hasDeviceString(DeviceString *o)
|
||||
{
|
||||
return (findDeviceString(o) >= 0);
|
||||
}
|
||||
|
||||
int
|
||||
DeviceStringParser::findDeviceString(DeviceString *o)
|
||||
{
|
||||
int i=0;
|
||||
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
|
||||
it != m_DeviceStrings.end();
|
||||
++it )
|
||||
{
|
||||
if(*it == o) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStringParser::pruneDuplicates()
|
||||
{
|
||||
DeviceStringVector duplicates;
|
||||
// find duplicates
|
||||
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
|
||||
it != m_DeviceStrings.end();
|
||||
++it )
|
||||
{
|
||||
for ( DeviceStringVectorIterator it2 = it+1;
|
||||
it2 != m_DeviceStrings.end();
|
||||
++it2 )
|
||||
{
|
||||
|
||||
if(**it == **it2) {
|
||||
duplicates.push_back(*it2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicates
|
||||
for ( DeviceStringVectorIterator it = duplicates.begin();
|
||||
it != duplicates.end();
|
||||
++it )
|
||||
{
|
||||
removeDeviceString(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStringParser::show()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_INFO, "DeviceStringParser: %p\n", this);
|
||||
for ( DeviceStringVectorIterator it = m_DeviceStrings.begin();
|
||||
it != m_DeviceStrings.end();
|
||||
++it )
|
||||
{
|
||||
(*it)->show();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeviceStringParser::setVerboseLevel(int i)
|
||||
{
|
||||
setDebugLevel(i);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FFADO_DEVICESTRINGPARSER__
|
||||
#define __FFADO_DEVICESTRINGPARSER__
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
class ConfigRom;
|
||||
|
||||
class DeviceStringParser {
|
||||
|
||||
protected:
|
||||
class DeviceString {
|
||||
public:
|
||||
enum eType {
|
||||
eInvalid = 0,
|
||||
eBusNode = 1, // old-style hw:bus,node
|
||||
eGUID = 2, // GUID match
|
||||
};
|
||||
|
||||
DeviceString(DeviceStringParser&);
|
||||
~DeviceString();
|
||||
|
||||
bool parse(std::string s);
|
||||
bool match(ConfigRom &);
|
||||
|
||||
std::string getString() {return m_String;};
|
||||
void show();
|
||||
|
||||
bool operator==(const DeviceString& x);
|
||||
static bool isValidString(std::string s);
|
||||
|
||||
private:
|
||||
DeviceStringParser & m_Parent;
|
||||
|
||||
int m_node;
|
||||
int m_port;
|
||||
uint64_t m_guid;
|
||||
std::string m_String;
|
||||
enum eType m_Type;
|
||||
|
||||
DECLARE_DEBUG_MODULE_REFERENCE;
|
||||
};
|
||||
|
||||
public:
|
||||
DeviceStringParser();
|
||||
virtual ~DeviceStringParser();
|
||||
|
||||
int countDeviceStrings() {return m_DeviceStrings.size();};
|
||||
|
||||
bool match(ConfigRom &);
|
||||
int matchPosition(ConfigRom& c);
|
||||
|
||||
bool parseString(std::string s);
|
||||
void show();
|
||||
void setVerboseLevel(int i);
|
||||
|
||||
static bool isValidString(std::string s);
|
||||
|
||||
protected:
|
||||
bool removeDeviceString(DeviceString *);
|
||||
bool addDeviceString(DeviceString *);
|
||||
bool hasDeviceString(DeviceString *);
|
||||
|
||||
private:
|
||||
int findDeviceString(DeviceString *);
|
||||
|
||||
void pruneDuplicates();
|
||||
|
||||
typedef std::vector< DeviceString* > DeviceStringVector;
|
||||
typedef std::vector< DeviceString* >::iterator DeviceStringVectorIterator;
|
||||
DeviceStringVector m_DeviceStrings;
|
||||
|
||||
protected:
|
||||
DECLARE_DEBUG_MODULE;
|
||||
|
||||
};
|
||||
|
||||
#endif /* __FFADO_DEVICESTRINGPARSER__ */
|
||||
|
||||
|
|
@ -0,0 +1,350 @@
|
|||
#
|
||||
# Copyright (C) 2007-2008 Arnold Krille
|
||||
# Copyright (C) 2007-2008 Pieter Palmers
|
||||
#
|
||||
# This file is part of FFADO
|
||||
# FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
#
|
||||
# FFADO is based upon FreeBoB.
|
||||
#
|
||||
# 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) version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import os
|
||||
|
||||
Import( 'env' )
|
||||
|
||||
libenv = env.Clone()
|
||||
|
||||
libenv.MergeFlags( "-I#/ -I#/src" )
|
||||
|
||||
ffado_source = env.Split( '\
|
||||
devicemanager.cpp \
|
||||
ffado.cpp \
|
||||
ffadodevice.cpp \
|
||||
debugmodule/debugmodule.cpp \
|
||||
DeviceStringParser.cpp \
|
||||
libieee1394/ARMHandler.cpp \
|
||||
libieee1394/configrom.cpp \
|
||||
libieee1394/csr1212.c \
|
||||
libieee1394/CycleTimerHelper.cpp \
|
||||
libieee1394/ieee1394service.cpp \
|
||||
libieee1394/IEC61883.cpp \
|
||||
libieee1394/IsoHandlerManager.cpp \
|
||||
libstreaming/StreamProcessorManager.cpp \
|
||||
libstreaming/util/cip.c \
|
||||
libstreaming/generic/StreamProcessor.cpp \
|
||||
libstreaming/generic/Port.cpp \
|
||||
libstreaming/generic/PortManager.cpp \
|
||||
libutil/cmd_serialize.cpp \
|
||||
libutil/DelayLockedLoop.cpp \
|
||||
libutil/IpcRingBuffer.cpp \
|
||||
libutil/PacketBuffer.cpp \
|
||||
libutil/Configuration.cpp \
|
||||
libutil/OptionContainer.cpp \
|
||||
libutil/PosixMessageQueue.cpp \
|
||||
libutil/PosixSharedMemory.cpp \
|
||||
libutil/PosixMutex.cpp \
|
||||
libutil/PosixThread.cpp \
|
||||
libutil/ringbuffer.c \
|
||||
libutil/StreamStatistics.cpp \
|
||||
libutil/SystemTimeSource.cpp \
|
||||
libutil/TimestampedBuffer.cpp \
|
||||
libutil/Watchdog.cpp \
|
||||
libcontrol/Element.cpp \
|
||||
libcontrol/BasicElements.cpp \
|
||||
libcontrol/MatrixMixer.cpp \
|
||||
libcontrol/CrossbarRouter.cpp \
|
||||
libcontrol/ClockSelect.cpp \
|
||||
libcontrol/Nickname.cpp \
|
||||
')
|
||||
|
||||
if env['SERIALIZE_USE_EXPAT']:
|
||||
ffado_source.append('libutil/serialize_expat.cpp')
|
||||
ffado_source.append('libutil/serialize_expat_xml.cpp')
|
||||
else:
|
||||
ffado_source.append('libutil/serialize_libxml.cpp')
|
||||
|
||||
bebob_source = env.Split( '\
|
||||
bebob/bebob_avdevice.cpp \
|
||||
bebob/bebob_avdevice_subunit.cpp \
|
||||
bebob/bebob_avplug.cpp \
|
||||
bebob/bebob_dl_bcd.cpp \
|
||||
bebob/bebob_dl_codes.cpp \
|
||||
bebob/bebob_dl_mgr.cpp \
|
||||
bebob/bebob_functionblock.cpp \
|
||||
bebob/bebob_mixer.cpp \
|
||||
bebob/focusrite/focusrite_generic.cpp \
|
||||
bebob/focusrite/focusrite_saffire.cpp \
|
||||
bebob/focusrite/focusrite_saffirepro.cpp \
|
||||
bebob/focusrite/focusrite_cmd.cpp \
|
||||
bebob/terratec/terratec_device.cpp \
|
||||
bebob/terratec/terratec_cmd.cpp \
|
||||
bebob/edirol/edirol_fa101.cpp \
|
||||
bebob/edirol/edirol_fa66.cpp \
|
||||
bebob/esi/quatafire610.cpp \
|
||||
bebob/mackie/onyxmixer.cpp \
|
||||
bebob/yamaha/yamaha_cmd.cpp \
|
||||
bebob/yamaha/yamaha_avdevice.cpp \
|
||||
bebob/maudio/normal_avdevice.cpp \
|
||||
bebob/maudio/special_avdevice.cpp \
|
||||
bebob/maudio/special_mixer.cpp \
|
||||
bebob/presonus/firebox_avdevice.cpp \
|
||||
bebob/presonus/inspire1394_avdevice.cpp \
|
||||
' )
|
||||
|
||||
bebob_pkgdata = env.Split( '\
|
||||
bebob/maudio/refdesign.xml \
|
||||
bebob/maudio/fw410.xml \
|
||||
bebob/maudio/fwap.xml \
|
||||
' )
|
||||
|
||||
genericavc_source = env.Split( '\
|
||||
genericavc/avc_avdevice.cpp \
|
||||
genericavc/stanton/scs.cpp \
|
||||
' )
|
||||
|
||||
genericavc_pkgdata = env.Split( '\
|
||||
' )
|
||||
|
||||
fireworks_source = env.Split( '\
|
||||
fireworks/fireworks_device.cpp \
|
||||
fireworks/fireworks_control.cpp \
|
||||
fireworks/fireworks_firmware.cpp \
|
||||
fireworks/efc/efc_avc_cmd.cpp \
|
||||
fireworks/efc/efc_cmd.cpp \
|
||||
fireworks/efc/efc_cmds_hardware.cpp \
|
||||
fireworks/efc/efc_cmds_hardware_ctrl.cpp \
|
||||
fireworks/efc/efc_cmds_flash.cpp \
|
||||
fireworks/efc/efc_cmds_mixer.cpp \
|
||||
fireworks/efc/efc_cmds_monitor.cpp \
|
||||
fireworks/efc/efc_cmds_ioconfig.cpp \
|
||||
fireworks/fireworks_session_block.cpp \
|
||||
fireworks/audiofire/audiofire_device.cpp \
|
||||
' )
|
||||
|
||||
fireworks_pkgdata = env.Split( '\
|
||||
' )
|
||||
|
||||
oxford_source = env.Split( '\
|
||||
oxford/oxford_device.cpp \
|
||||
libstreaming/amdtp-oxford/AmdtpOxfordReceiveStreamProcessor.cpp \
|
||||
' )
|
||||
|
||||
oxford_pkgdata = env.Split( '\
|
||||
' )
|
||||
|
||||
motu_source = env.Split( '\
|
||||
motu/motu_avdevice.cpp \
|
||||
motu/motu_controls.cpp \
|
||||
motu/motu_mark3_controls.cpp \
|
||||
motu/motu_mixerdefs.cpp \
|
||||
motu/motu_mark3_mixerdefs.cpp \
|
||||
motu/motu_mixer.cpp \
|
||||
libstreaming/motu/MotuPort.cpp \
|
||||
libstreaming/motu/MotuPortInfo.cpp \
|
||||
libstreaming/motu/MotuReceiveStreamProcessor.cpp \
|
||||
libstreaming/motu/MotuTransmitStreamProcessor.cpp \
|
||||
' )
|
||||
|
||||
dice_source = env.Split( '\
|
||||
dice/dice_avdevice.cpp \
|
||||
dice/dice_firmware_loader.cpp \
|
||||
dice/dice_eap.cpp \
|
||||
dice/focusrite/focusrite_eap.cpp \
|
||||
dice/focusrite/saffire_pro40.cpp \
|
||||
dice/focusrite/saffire_pro26.cpp \
|
||||
dice/focusrite/saffire_pro24.cpp \
|
||||
dice/focusrite/saffire_pro14.cpp \
|
||||
dice/focusrite/saffire_56.cpp \
|
||||
dice/maudio/profire_2626.cpp \
|
||||
dice/presonus/firestudio_tube.cpp \
|
||||
dice/presonus/firestudio_project.cpp \
|
||||
dice/presonus/firestudio_mobile.cpp \
|
||||
' )
|
||||
|
||||
bounce_source = env.Split( '\
|
||||
bounce/bounce_avdevice.cpp \
|
||||
bounce/bounce_slave_avdevice.cpp \
|
||||
' )
|
||||
|
||||
metric_halo_source = env.Split( '\
|
||||
metrichalo/mh_avdevice.cpp \
|
||||
' )
|
||||
|
||||
rme_source = env.Split( '\
|
||||
rme/rme_shm.cpp \
|
||||
rme/rme_avdevice.cpp \
|
||||
rme/rme_avdevice_settings.cpp \
|
||||
rme/fireface_flash.cpp \
|
||||
rme/fireface_hw.cpp \
|
||||
rme/fireface_settings_ctrls.cpp \
|
||||
libstreaming/rme/RmePort.cpp \
|
||||
libstreaming/rme/RmePortInfo.cpp \
|
||||
libstreaming/rme/RmeReceiveStreamProcessor.cpp \
|
||||
libstreaming/rme/RmeTransmitStreamProcessor.cpp \
|
||||
' )
|
||||
|
||||
digidesign_source = env.Split( '\
|
||||
digidesign/digidesign_avdevice.cpp \
|
||||
libstreaming/digidesign/DigidesignPort.cpp \
|
||||
libstreaming/digidesign/DigidesignPortInfo.cpp \
|
||||
libstreaming/digidesign/DigidesignReceiveStreamProcessor.cpp \
|
||||
libstreaming/digidesign/DigidesignTransmitStreamProcessor.cpp \
|
||||
' )
|
||||
|
||||
amdtp_source = env.Split( '\
|
||||
libstreaming/amdtp/AmdtpPort.cpp \
|
||||
libstreaming/amdtp/AmdtpPortInfo.cpp \
|
||||
libstreaming/amdtp/AmdtpReceiveStreamProcessor.cpp \
|
||||
libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp \
|
||||
' )
|
||||
|
||||
libavc_source = env.Split( '\
|
||||
libavc/streamformat/avc_extended_stream_format.cpp \
|
||||
libavc/musicsubunit/avc_descriptor_music.cpp \
|
||||
libavc/musicsubunit/avc_musicsubunit.cpp \
|
||||
libavc/audiosubunit/avc_audiosubunit.cpp \
|
||||
libavc/audiosubunit/avc_descriptor_audio.cpp \
|
||||
libavc/audiosubunit/avc_function_block.cpp \
|
||||
libavc/descriptors/avc_descriptor_cmd.cpp \
|
||||
libavc/descriptors/avc_descriptor.cpp \
|
||||
libavc/general/avc_extended_subunit_info.cpp \
|
||||
libavc/general/avc_unit_info.cpp \
|
||||
libavc/general/avc_generic.cpp \
|
||||
libavc/general/avc_subunit_info.cpp \
|
||||
libavc/general/avc_connect.cpp \
|
||||
libavc/general/avc_signal_format.cpp \
|
||||
libavc/general/avc_extended_cmd_generic.cpp \
|
||||
libavc/general/avc_extended_plug_info.cpp \
|
||||
libavc/general/avc_plug_info.cpp \
|
||||
libavc/general/avc_unit.cpp \
|
||||
libavc/general/avc_subunit.cpp \
|
||||
libavc/general/avc_plug.cpp \
|
||||
libavc/general/avc_vendor_dependent_cmd.cpp \
|
||||
libavc/avc_definitions.cpp \
|
||||
libavc/ccm/avc_signal_source.cpp \
|
||||
' )
|
||||
|
||||
source = ffado_source
|
||||
pkgdata = []
|
||||
if env['ENABLE_BEBOB']:
|
||||
env['ENABLE_GENERICAVC'] = True
|
||||
libenv.MergeFlags( "-DENABLE_BEBOB" )
|
||||
source += bebob_source
|
||||
pkgdata += bebob_pkgdata
|
||||
if env['ENABLE_FIREWORKS']:
|
||||
env['ENABLE_GENERICAVC'] = True
|
||||
libenv.MergeFlags( "-DENABLE_FIREWORKS" )
|
||||
source += fireworks_source
|
||||
pkgdata += fireworks_pkgdata
|
||||
if env['ENABLE_OXFORD']:
|
||||
env['ENABLE_GENERICAVC'] = True
|
||||
libenv.MergeFlags( "-DENABLE_OXFORD" )
|
||||
source += oxford_source
|
||||
pkgdata += oxford_pkgdata
|
||||
if env['ENABLE_MOTU']:
|
||||
libenv.MergeFlags( "-DENABLE_MOTU" )
|
||||
source += motu_source
|
||||
if env['ENABLE_DICE']:
|
||||
env['ENABLE_GENERICAVC'] = True
|
||||
libenv.MergeFlags( "-DENABLE_DICE" )
|
||||
source += dice_source
|
||||
if env['ENABLE_METRIC_HALO']:
|
||||
libenv.MergeFlags( "-DENABLE_METRIC_HALO" )
|
||||
source += metric_halo_source
|
||||
if env['ENABLE_RME']:
|
||||
libenv.MergeFlags( "-DENABLE_RME" )
|
||||
source += rme_source
|
||||
if env['ENABLE_DIGIDESIGN']:
|
||||
libenv.MergeFlags( "-DENABLE_DIGIDESIGN" )
|
||||
source += digidesign_source
|
||||
if env['ENABLE_BOUNCE']:
|
||||
env['ENABLE_GENERICAVC'] = True
|
||||
libenv.MergeFlags( "-DENABLE_BOUNCE" )
|
||||
source += bounce_source
|
||||
|
||||
if env['ENABLE_GENERICAVC']:
|
||||
libenv.MergeFlags( "-DENABLE_GENERICAVC" )
|
||||
source += libavc_source
|
||||
source += amdtp_source
|
||||
source += genericavc_source
|
||||
pkgdata += genericavc_pkgdata
|
||||
|
||||
if not env.GetOption( "clean" ):
|
||||
libenv.MergeFlags( "-lrt -lpthread" )
|
||||
libenv.MergeFlags( env['LIBRAW1394_FLAGS'].decode() )
|
||||
libenv.MergeFlags( env['LIBIEC61883_FLAGS'].decode() )
|
||||
libenv.MergeFlags( env['LIBCONFIG_FLAGS'].decode() )
|
||||
if not env['SERIALIZE_USE_EXPAT']:
|
||||
if 'LIBXML30_FLAGS' in env :
|
||||
libenv.MergeFlags( env['LIBXML30_FLAGS'].decode() )
|
||||
if not('LIBXML30_FLAGS' in env) :
|
||||
libenv.MergeFlags( env['LIBXML26_FLAGS'].decode() )
|
||||
else:
|
||||
libenv.PrependUnique( LIBS=["expat"] )
|
||||
libenv.MergeFlags( "-DSERIALIZE_USE_EXPAT" )
|
||||
if env['REQUIRE_LIBAVC']:
|
||||
libenv.MergeFlags( env['LIBAVC1394_FLAGS'].decode() )
|
||||
|
||||
libname_versioned = "libffado.so.%s" % libenv['VERSION']
|
||||
libname_versioned_short = "libffado.so.%s" % libenv['VERSION'].split('.')[0]
|
||||
|
||||
libenv.MergeFlags( "-Wl,-soname=%s" % libname_versioned_short )
|
||||
ffadolib = libenv.SharedLibrary( "ffado", source )
|
||||
|
||||
#libenv.Install( "$libdir", ffadolib )
|
||||
installer = libenv.InstallAs ( "$libdir/%s" % libname_versioned , ffadolib )
|
||||
|
||||
# if stripping would be something for us
|
||||
#libenv.AddPostAction(installer, [['strip', env['STRIPFLAGS'], t[0].path]])
|
||||
|
||||
# make the required links
|
||||
libenv.NoCache( '$libdir/%s' % libname_versioned )
|
||||
libenv.AddPostAction(installer, [['rm', '-f', '$libdir/libffado.so', '$libdir/%s' % libname_versioned_short],
|
||||
['cd', '$libdir',
|
||||
'&&','ln', '-s', libname_versioned_short, 'libffado.so',
|
||||
'&&','ln', '-s', installer[0].name, libname_versioned_short,
|
||||
]
|
||||
])
|
||||
|
||||
if libenv['BUILD_STATIC_LIB']:
|
||||
ffadolib_static = libenv.StaticLibrary( "ffado", source )
|
||||
|
||||
#
|
||||
# Install the pkgdata to $sharedir
|
||||
#
|
||||
for data in pkgdata:
|
||||
libenv.Install( "$sharedir", data )
|
||||
|
||||
#
|
||||
# For the debugging apps
|
||||
#
|
||||
env2 = libenv.Clone()
|
||||
env2.PrependUnique( LIBPATH=env['build_base']+"src" )
|
||||
env2.PrependUnique( LIBS="ffado" )
|
||||
|
||||
apps = { \
|
||||
"test-debugmodule" : "debugmodule/test_debugmodule.cpp", \
|
||||
"test-dll" : "libutil/test-dll.cpp", \
|
||||
"test-unittests-util" : "libutil/unittests.cpp", \
|
||||
"test-cyclecalc" : "libieee1394/test-cyclecalc.cpp", \
|
||||
}
|
||||
|
||||
installapps = []
|
||||
|
||||
for app in apps.keys():
|
||||
env2.Program( target=app, source = env.Split( apps[app] ) )
|
||||
if app.find( "test" ) == -1:
|
||||
env2.Install( "$bindir", app )
|
|
@ -0,0 +1,927 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "devicemanager.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
#include "bebob/bebob_avdevice_subunit.h"
|
||||
#include "bebob/bebob_mixer.h"
|
||||
|
||||
#include "bebob/focusrite/focusrite_saffire.h"
|
||||
#include "bebob/focusrite/focusrite_saffirepro.h"
|
||||
#include "bebob/terratec/terratec_device.h"
|
||||
#include "bebob/mackie/onyxmixer.h"
|
||||
#include "bebob/edirol/edirol_fa101.h"
|
||||
#include "bebob/edirol/edirol_fa66.h"
|
||||
#include "bebob/esi/quatafire610.h"
|
||||
#include "bebob/yamaha/yamaha_avdevice.h"
|
||||
#include "bebob/maudio/normal_avdevice.h"
|
||||
#include "bebob/maudio/special_avdevice.h"
|
||||
#include "bebob/presonus/firebox_avdevice.h"
|
||||
#include "bebob/presonus/inspire1394_avdevice.h"
|
||||
|
||||
#include "libieee1394/configrom.h"
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
#include "libavc/general/avc_plug_info.h"
|
||||
#include "libavc/general/avc_extended_plug_info.h"
|
||||
#include "libavc/general/avc_subunit_info.h"
|
||||
#include "libavc/streamformat/avc_extended_stream_format.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
#include "libavc/avc_definitions.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/stat.h>
|
||||
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
Device::Device( DeviceManager& d, ffado_smartptr< ConfigRom >( configRom ) )
|
||||
: GenericAVC::Device( d, configRom )
|
||||
, m_last_discovery_config_id ( 0xFFFFFFFFFFFFFFFFLLU )
|
||||
, m_Mixer ( 0 )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
destroyMixer();
|
||||
}
|
||||
|
||||
bool
|
||||
Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
|
||||
{
|
||||
unsigned int vendorId = configRom.getNodeVendorId();
|
||||
unsigned int modelId = configRom.getModelId();
|
||||
|
||||
if(generic) {
|
||||
/* M-Audio Special Devices don't support followed commands */
|
||||
if ((vendorId == FW_VENDORID_MAUDIO) &&
|
||||
((modelId == 0x00010071) || (modelId == 0x00010091)))
|
||||
return true;
|
||||
|
||||
// try a bebob-specific command to check for the firmware
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd( configRom.get1394Service() );
|
||||
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
|
||||
configRom.getNodeId() );
|
||||
extPlugInfoCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
|
||||
PlugAddress::ePAM_Unit,
|
||||
unitPlugAddress ) );
|
||||
extPlugInfoCmd.setNodeId( configRom.getNodeId() );
|
||||
extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
extPlugInfoCmd.setVerbose( configRom.getVerboseLevel() );
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_NoOfChannels );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "Number of channels command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if((extPlugInfoCmd.getResponse() != AVCCommand::eR_Implemented)) {
|
||||
// command not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugNrOfChns )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// check if device is in supported devices list
|
||||
Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
|
||||
return c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB;
|
||||
}
|
||||
}
|
||||
|
||||
FFADODevice *
|
||||
Device::createDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
{
|
||||
unsigned int vendorId = configRom->getNodeVendorId();
|
||||
unsigned int modelId = configRom->getModelId();
|
||||
|
||||
switch (vendorId) {
|
||||
case FW_VENDORID_MACKIE:
|
||||
if (modelId == 0x00010065 ) {
|
||||
return new Mackie::OnyxMixerDevice(d, configRom);
|
||||
}
|
||||
case FW_VENDORID_EDIROL:
|
||||
switch (modelId) {
|
||||
case 0x00010048:
|
||||
return new Edirol::EdirolFa101Device(d, configRom);
|
||||
case 0x00010049:
|
||||
return new Edirol::EdirolFa66Device(d, configRom);
|
||||
default:
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
case FW_VENDORID_ESI:
|
||||
if (modelId == 0x00010064 || modelId == 0x00000210) {
|
||||
return new ESI::QuataFireDevice(d, configRom);
|
||||
}
|
||||
break;
|
||||
case FW_VENDORID_TERRATEC:
|
||||
switch(modelId) {
|
||||
case 0x00000003:
|
||||
return new Terratec::Phase88Device(d, configRom);
|
||||
default: // return a plain BeBoB device
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
case FW_VENDORID_FOCUSRITE:
|
||||
switch(modelId) {
|
||||
case 0x00000003:
|
||||
case 0x00000006:
|
||||
return new Focusrite::SaffireProDevice(d, configRom);
|
||||
case 0x00000000:
|
||||
return new Focusrite::SaffireDevice(d, configRom);
|
||||
default: // return a plain BeBoB device
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
case FW_VENDORID_YAMAHA:
|
||||
switch (modelId) {
|
||||
case 0x0010000b:
|
||||
case 0x0010000c:
|
||||
return new Yamaha::GoDevice(d, configRom);
|
||||
default: // return a plain BeBoB device
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
case FW_VENDORID_MAUDIO:
|
||||
switch (modelId) {
|
||||
case 0x0000000a: // Ozonic
|
||||
case 0x00010046: // fw410
|
||||
case 0x00010060: // Audiophile
|
||||
case 0x00010062: // Solo
|
||||
return new MAudio::Normal::Device(d, configRom, modelId);
|
||||
case 0x00010071: // FireWire 1814
|
||||
case 0x00010091: // ProjectMix I/O
|
||||
return new MAudio::Special::Device(d, configRom);
|
||||
default:
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
case FW_VENDORID_PRESONUS:
|
||||
switch (modelId) {
|
||||
case 0x00010000:
|
||||
return new Presonus::Firebox::Device(d, configRom);
|
||||
case 0x00010001:
|
||||
return new Presonus::Inspire1394::Device(d, configRom);
|
||||
default:
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
default:
|
||||
return new Device(d, configRom);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define BEBOB_CHECK_AND_ADD_SR(v, x) \
|
||||
{ if(supportsSamplingFrequency(x)) \
|
||||
v.push_back(x); }
|
||||
bool
|
||||
Device::discover()
|
||||
{
|
||||
unsigned int vendorId = getConfigRom().getNodeVendorId();
|
||||
unsigned int modelId = getConfigRom().getModelId();
|
||||
|
||||
Util::Configuration &c = getDeviceManager().getConfiguration();
|
||||
Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
|
||||
|
||||
if (c.isValid(vme) && vme.driver == Util::Configuration::eD_BeBoB) {
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
|
||||
vme.vendor_name.c_str(),
|
||||
vme.model_name.c_str());
|
||||
} else {
|
||||
debugWarning("Using generic BeBoB support for unsupported device '%s %s'\n",
|
||||
getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
|
||||
}
|
||||
|
||||
if ( !Unit::discover() ) {
|
||||
debugError( "Could not discover unit\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if((getAudioSubunit( 0 ) == NULL)) {
|
||||
debugError( "Unit doesn't have an Audio subunit.\n");
|
||||
return false;
|
||||
}
|
||||
if((getMusicSubunit( 0 ) == NULL)) {
|
||||
debugError( "Unit doesn't have a Music subunit.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!buildMixer()) {
|
||||
debugWarning("Could not build mixer\n");
|
||||
}
|
||||
|
||||
// keep track of the config id of this discovery
|
||||
m_last_discovery_config_id = getConfigurationId();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::buildMixer()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Building a generic BeBoB mixer...\n");
|
||||
// create a Mixer
|
||||
// this removes the mixer if it already exists
|
||||
// note: a mixer self-registers to it's parent
|
||||
delete m_Mixer;
|
||||
|
||||
// create the mixer & register it
|
||||
if(getAudioSubunit(0) == NULL) {
|
||||
debugWarning("Could not find audio subunit, mixer not available.\n");
|
||||
m_Mixer = NULL;
|
||||
} else {
|
||||
m_Mixer = new Mixer(*this);
|
||||
}
|
||||
if (m_Mixer) m_Mixer->setVerboseLevel(getDebugLevel());
|
||||
return m_Mixer != NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::destroyMixer()
|
||||
{
|
||||
delete m_Mixer;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setSelectorFBValue(int id, int value) {
|
||||
FunctionBlockCmd fbCmd( get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Selector,
|
||||
id,
|
||||
FunctionBlockCmd::eCA_Current );
|
||||
fbCmd.setNodeId( getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Control );
|
||||
fbCmd.m_pFBSelector->m_inputFbPlugNumber = (value & 0xFF);
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
//
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
|
||||
}
|
||||
|
||||
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getSelectorFBValue(int id) {
|
||||
|
||||
FunctionBlockCmd fbCmd( get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Selector,
|
||||
id,
|
||||
FunctionBlockCmd::eCA_Current );
|
||||
fbCmd.setNodeId( getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
fbCmd.m_pFBSelector->m_inputFbPlugNumber = 0xFF;
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
|
||||
}
|
||||
|
||||
return fbCmd.m_pFBSelector->m_inputFbPlugNumber;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setFeatureFBVolumeCurrent(int id, int channel, int v) {
|
||||
|
||||
FunctionBlockCmd fbCmd( get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Feature,
|
||||
id,
|
||||
FunctionBlockCmd::eCA_Current );
|
||||
fbCmd.setNodeId( getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Control );
|
||||
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
|
||||
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
|
||||
AVC::FunctionBlockFeatureVolume vl;
|
||||
fbCmd.m_pFBFeature->m_pVolume = vl.clone();
|
||||
fbCmd.m_pFBFeature->m_pVolume->m_volume = v;
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
|
||||
}
|
||||
|
||||
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBVolumeValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
|
||||
{
|
||||
FunctionBlockCmd fbCmd( get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Feature,
|
||||
id,
|
||||
controlAttribute);
|
||||
fbCmd.setNodeId( getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
|
||||
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_Volume;
|
||||
AVC::FunctionBlockFeatureVolume vl;
|
||||
fbCmd.m_pFBFeature->m_pVolume = vl.clone();
|
||||
fbCmd.m_pFBFeature->m_pVolume->m_volume = 0;
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
|
||||
}
|
||||
|
||||
int16_t volume=(int16_t)(fbCmd.m_pFBFeature->m_pVolume->m_volume);
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBVolumeMinimum(int id, int channel)
|
||||
{
|
||||
return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBVolumeMaximum(int id, int channel)
|
||||
{
|
||||
return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBVolumeCurrent(int id, int channel)
|
||||
{
|
||||
return getFeatureFBVolumeValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setFeatureFBLRBalanceCurrent(int id, int channel, int v) {
|
||||
|
||||
FunctionBlockCmd fbCmd( get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Feature,
|
||||
id,
|
||||
FunctionBlockCmd::eCA_Current );
|
||||
fbCmd.setNodeId( getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Control );
|
||||
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
|
||||
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
|
||||
AVC::FunctionBlockFeatureLRBalance bl;
|
||||
fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
|
||||
fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = v;
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
|
||||
}
|
||||
|
||||
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBLRBalanceValue(int id, int channel, FunctionBlockCmd::EControlAttribute controlAttribute)
|
||||
{
|
||||
FunctionBlockCmd fbCmd( get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Feature,
|
||||
id,
|
||||
controlAttribute);
|
||||
fbCmd.setNodeId( getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
fbCmd.m_pFBFeature->m_audioChannelNumber = channel;
|
||||
fbCmd.m_pFBFeature->m_controlSelector = FunctionBlockFeature::eCSE_Feature_LRBalance;
|
||||
AVC::FunctionBlockFeatureLRBalance bl;
|
||||
fbCmd.m_pFBFeature->m_pLRBalance = bl.clone();
|
||||
fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance = 0;
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
|
||||
}
|
||||
|
||||
int16_t balance=(int16_t)(fbCmd.m_pFBFeature->m_pLRBalance->m_lrBalance);
|
||||
|
||||
return balance;
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBLRBalanceMinimum(int id, int channel)
|
||||
{
|
||||
return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Minimum);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBLRBalanceMaximum(int id, int channel)
|
||||
{
|
||||
return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Maximum);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getFeatureFBLRBalanceCurrent(int id, int channel)
|
||||
{
|
||||
return getFeatureFBLRBalanceValue(id, channel, AVC::FunctionBlockCmd::eCA_Current);
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
|
||||
int iAChNum, int oAChNum,
|
||||
int setting)
|
||||
{
|
||||
AVC::FunctionBlockCmd fbCmd(get1394Service(),
|
||||
AVC::FunctionBlockCmd::eFBT_Processing,
|
||||
id,
|
||||
AVC::FunctionBlockCmd::eCA_Current);
|
||||
fbCmd.setNodeId(getNodeId());
|
||||
fbCmd.setSubunitId(0x00);
|
||||
fbCmd.setCommandType(AVCCommand::eCT_Control);
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
|
||||
fbp->m_selectorLength = 0x04;
|
||||
fbp->m_fbInputPlugNumber = iPlugNum;
|
||||
fbp->m_inputAudioChannelNumber = iAChNum;
|
||||
fbp->m_outputAudioChannelNumber = oAChNum;
|
||||
|
||||
// mixer object is not generated automatically
|
||||
fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
|
||||
fbp->m_pMixer->m_mixerSetting = setting;
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Accepted)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Accepted\n");
|
||||
}
|
||||
|
||||
return (fbCmd.getResponse() == AVCCommand::eR_Accepted);
|
||||
}
|
||||
|
||||
int
|
||||
Device::getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
|
||||
int iAChNum, int oAChNum)
|
||||
{
|
||||
AVC::FunctionBlockCmd fbCmd(get1394Service(),
|
||||
AVC::FunctionBlockCmd::eFBT_Processing,
|
||||
id,
|
||||
AVC::FunctionBlockCmd::eCA_Current);
|
||||
fbCmd.setNodeId(getNodeId());
|
||||
fbCmd.setSubunitId(0x00);
|
||||
fbCmd.setCommandType(AVCCommand::eCT_Status);
|
||||
fbCmd.setVerboseLevel( getDebugLevel() );
|
||||
|
||||
AVC::FunctionBlockProcessing *fbp = fbCmd.m_pFBProcessing;
|
||||
fbp->m_selectorLength = 0x04;
|
||||
fbp->m_fbInputPlugNumber = iPlugNum;
|
||||
fbp->m_inputAudioChannelNumber = iAChNum;
|
||||
fbp->m_outputAudioChannelNumber = oAChNum;
|
||||
|
||||
// mixer object is not generated automatically
|
||||
fbp->m_pMixer = new AVC::FunctionBlockProcessingMixer;
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( (fbCmd.getResponse() != AVCCommand::eR_Implemented) ) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
|
||||
}
|
||||
|
||||
int16_t setting = (int16_t)(fbp->m_pMixer->m_mixerSetting);
|
||||
|
||||
return setting;
|
||||
}
|
||||
|
||||
void
|
||||
Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Device is a BeBoB device\n");
|
||||
GenericAVC::Device::showDevice();
|
||||
flushDebugOutput();
|
||||
}
|
||||
|
||||
void
|
||||
Device::setVerboseLevel(int l)
|
||||
{
|
||||
if (m_Mixer) m_Mixer->setVerboseLevel( l );
|
||||
GenericAVC::Device::setVerboseLevel( l );
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
|
||||
}
|
||||
|
||||
AVC::Subunit*
|
||||
Device::createSubunit(AVC::Unit& unit,
|
||||
AVC::ESubunitType type,
|
||||
AVC::subunit_t id )
|
||||
{
|
||||
AVC::Subunit* s=NULL;
|
||||
switch (type) {
|
||||
case eST_Audio:
|
||||
s=new BeBoB::SubunitAudio(unit, id );
|
||||
break;
|
||||
case eST_Music:
|
||||
s=new BeBoB::SubunitMusic(unit, id );
|
||||
break;
|
||||
default:
|
||||
s=NULL;
|
||||
break;
|
||||
}
|
||||
if(s) s->setVerboseLevel(getDebugLevel());
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
AVC::Plug *
|
||||
Device::createPlug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId,
|
||||
int globalId )
|
||||
{
|
||||
|
||||
Plug *p= new BeBoB::Plug( unit,
|
||||
subunit,
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId,
|
||||
globalId );
|
||||
if (p) p->setVerboseLevel(getDebugLevel());
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::propagatePlugInfo() {
|
||||
// we don't have to propagate since we discover things
|
||||
// another way
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Skip plug info propagation\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
Device::getConfigurationIdSampleRate()
|
||||
{
|
||||
ExtendedStreamFormatCmd extStreamFormatCmd( get1394Service() );
|
||||
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR, 0 );
|
||||
extStreamFormatCmd.setPlugAddress( PlugAddress( PlugAddress::ePD_Input,
|
||||
PlugAddress::ePAM_Unit,
|
||||
unitPlugAddress ) );
|
||||
|
||||
extStreamFormatCmd.setNodeId( getNodeId() );
|
||||
extStreamFormatCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
extStreamFormatCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extStreamFormatCmd.fire() ) {
|
||||
debugError( "Stream format command failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
FormatInformation* formatInfo =
|
||||
extStreamFormatCmd.getFormatInformation();
|
||||
FormatInformationStreamsCompound* compoundStream
|
||||
= dynamic_cast< FormatInformationStreamsCompound* > (
|
||||
formatInfo->m_streams );
|
||||
if ( compoundStream ) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sample rate 0x%02x\n",
|
||||
compoundStream->m_samplingFrequency );
|
||||
return compoundStream->m_samplingFrequency;
|
||||
}
|
||||
|
||||
debugError( "Could not retrieve sample rate\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
Device::getConfigurationIdNumberOfChannel( PlugAddress::EPlugDirection ePlugDirection )
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd( get1394Service() );
|
||||
UnitPlugAddress unitPlugAddress( UnitPlugAddress::ePT_PCR,
|
||||
0 );
|
||||
extPlugInfoCmd.setPlugAddress( PlugAddress( ePlugDirection,
|
||||
PlugAddress::ePAM_Unit,
|
||||
unitPlugAddress ) );
|
||||
extPlugInfoCmd.setNodeId( getNodeId() );
|
||||
extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_NoOfChannels );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "Number of channels command failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugNrOfChns )
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Number of channels 0x%02x\n",
|
||||
infoType->m_plugNrOfChns->m_nrOfChannels );
|
||||
return infoType->m_plugNrOfChns->m_nrOfChannels;
|
||||
}
|
||||
|
||||
debugError( "Could not retrieve number of channels\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
Device::getConfigurationIdSyncMode()
|
||||
{
|
||||
SignalSourceCmd signalSourceCmd( get1394Service() );
|
||||
SignalUnitAddress signalUnitAddr;
|
||||
signalUnitAddr.m_plugId = 0x01;
|
||||
signalSourceCmd.setSignalDestination( signalUnitAddr );
|
||||
signalSourceCmd.setNodeId( getNodeId() );
|
||||
signalSourceCmd.setSubunitType( eST_Unit );
|
||||
signalSourceCmd.setSubunitId( 0xff );
|
||||
signalSourceCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
signalSourceCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
|
||||
if ( !signalSourceCmd.fire() ) {
|
||||
debugError( "Signal source command failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
SignalAddress* pSyncPlugSignalAddress = signalSourceCmd.getSignalSource();
|
||||
SignalSubunitAddress* pSyncPlugSubunitAddress
|
||||
= dynamic_cast<SignalSubunitAddress*>( pSyncPlugSignalAddress );
|
||||
if ( pSyncPlugSubunitAddress ) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
|
||||
( pSyncPlugSubunitAddress->m_subunitType << 3
|
||||
| pSyncPlugSubunitAddress->m_subunitId ) << 8
|
||||
| pSyncPlugSubunitAddress->m_plugId );
|
||||
|
||||
return ( pSyncPlugSubunitAddress->m_subunitType << 3
|
||||
| pSyncPlugSubunitAddress->m_subunitId ) << 8
|
||||
| pSyncPlugSubunitAddress->m_plugId;
|
||||
}
|
||||
|
||||
SignalUnitAddress* pSyncPlugUnitAddress
|
||||
= dynamic_cast<SignalUnitAddress*>( pSyncPlugSignalAddress );
|
||||
if ( pSyncPlugUnitAddress ) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
|
||||
0xff << 8 | pSyncPlugUnitAddress->m_plugId );
|
||||
|
||||
return ( 0xff << 8 | pSyncPlugUnitAddress->m_plugId );
|
||||
}
|
||||
|
||||
debugError( "Could not retrieve sync mode\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::needsRediscovery()
|
||||
{
|
||||
// require rediscovery if the config id differs from the one saved
|
||||
// in the previous discovery
|
||||
return getConfigurationId() != m_last_discovery_config_id;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Device::getConfigurationId()
|
||||
{
|
||||
// create a unique configuration id.
|
||||
uint64_t id = 0;
|
||||
id = getConfigurationIdSampleRate();
|
||||
id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Input ) << 8;
|
||||
id |= getConfigurationIdNumberOfChannel( PlugAddress::ePD_Output ) << 16;
|
||||
id |= ((uint64_t)getConfigurationIdSyncMode()) << 24;
|
||||
return id;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::serialize( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
bool result;
|
||||
result = GenericAVC::Device::serialize( basePath, ser );
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::deserialize( std::string basePath,
|
||||
Util::IODeserialize& deser )
|
||||
{
|
||||
bool result;
|
||||
result = GenericAVC::Device::deserialize( basePath, deser );
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string
|
||||
Device::getCachePath()
|
||||
{
|
||||
std::string cachePath;
|
||||
char* pCachePath;
|
||||
|
||||
string path = CACHEDIR;
|
||||
if ( path.size() && path[0] == '~' ) {
|
||||
path.erase( 0, 1 ); // remove ~
|
||||
path.insert( 0, getenv( "HOME" ) ); // prepend the home path
|
||||
}
|
||||
|
||||
if ( asprintf( &pCachePath, "%s/cache/", path.c_str() ) < 0 ) {
|
||||
debugError( "Could not create path string for cache pool (trying '/var/cache/libffado' instead)\n" );
|
||||
cachePath = "/var/cache/libffado/";
|
||||
} else {
|
||||
cachePath = pCachePath;
|
||||
free( pCachePath );
|
||||
}
|
||||
return cachePath;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::loadFromCache()
|
||||
{
|
||||
std::string sDevicePath = getCachePath() + getConfigRom().getGuidString();
|
||||
|
||||
char* configId;
|
||||
asprintf(&configId, "%016" PRIx64 "", getConfigurationId() );
|
||||
if ( !configId ) {
|
||||
debugError( "could not create id string\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string sFileName = sDevicePath + "/" + configId + ".xml";
|
||||
free( configId );
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", sFileName.c_str() );
|
||||
|
||||
struct stat buf;
|
||||
if ( stat( sFileName.c_str(), &buf ) != 0 ) {
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" does not exist\n", sFileName.c_str() );
|
||||
return false;
|
||||
} else {
|
||||
if ( !S_ISREG( buf.st_mode ) ) {
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "\"%s\" is not a regular file\n", sFileName.c_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Util::XMLDeserialize deser( sFileName, getDebugLevel() );
|
||||
|
||||
if (!deser.isValid()) {
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "cache not valid: %s\n",
|
||||
sFileName.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = deserialize( "", deser );
|
||||
if ( result ) {
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "could create valid bebob driver from %s\n",
|
||||
sFileName.c_str() );
|
||||
}
|
||||
|
||||
if(result) {
|
||||
buildMixer();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::saveCache()
|
||||
{
|
||||
// the path looks like this:
|
||||
// PATH_TO_CACHE + GUID + CONFIGURATION_ID
|
||||
string tmp_path = getCachePath() + getConfigRom().getGuidString();
|
||||
|
||||
// the following piece should do something like
|
||||
// 'mkdir -p some/path/with/some/dirs/which/do/not/exist'
|
||||
vector<string> tokens;
|
||||
tokenize( tmp_path, tokens, "/" );
|
||||
string path;
|
||||
for ( vector<string>::const_iterator it = tokens.begin();
|
||||
it != tokens.end();
|
||||
++it )
|
||||
{
|
||||
path += "/" + *it;
|
||||
|
||||
struct stat buf;
|
||||
if ( stat( path.c_str(), &buf ) == 0 ) {
|
||||
if ( !S_ISDIR( buf.st_mode ) ) {
|
||||
debugError( "\"%s\" is not a directory\n", path.c_str() );
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ( mkdir( path.c_str(), S_IRWXU | S_IRWXG ) != 0 ) {
|
||||
debugError( "Could not create \"%s\" directory\n", path.c_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// come up with an unique file name for the current settings
|
||||
char* configId;
|
||||
asprintf(&configId, "%016" PRIx64 "", BeBoB::Device::getConfigurationId() );
|
||||
if ( !configId ) {
|
||||
debugError( "Could not create id string\n" );
|
||||
return false;
|
||||
}
|
||||
string filename = path + "/" + configId + ".xml";
|
||||
free( configId );
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "filename %s\n", filename.c_str() );
|
||||
|
||||
Util::XMLSerialize ser( filename );
|
||||
return serialize( "", ser );
|
||||
}
|
||||
|
||||
} // end of namespace
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_DEVICE_H
|
||||
#define BEBOB_DEVICE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include "libieee1394/configrom.h"
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
#include "libavc/avc_definitions.h"
|
||||
#include "libavc/general/avc_extended_cmd_generic.h"
|
||||
#include "libavc/general/avc_unit.h"
|
||||
#include "libavc/general/avc_subunit.h"
|
||||
#include "libavc/general/avc_plug.h"
|
||||
#include "libavc/audiosubunit/avc_function_block.h"
|
||||
|
||||
#include "bebob/bebob_avplug.h"
|
||||
#include "bebob/bebob_avdevice_subunit.h"
|
||||
#include "bebob/bebob_mixer.h"
|
||||
|
||||
#include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h"
|
||||
#include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h"
|
||||
#include "libstreaming/amdtp/AmdtpPort.h"
|
||||
#include "libstreaming/amdtp/AmdtpPortInfo.h"
|
||||
|
||||
#include "libutil/serialize.h"
|
||||
|
||||
#include "genericavc/avc_avdevice.h"
|
||||
|
||||
#include "ffadodevice.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
class Device : public GenericAVC::Device {
|
||||
public:
|
||||
Device( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~Device();
|
||||
|
||||
static bool probe( Util::Configuration&, ConfigRom& configRom, bool generic = false );
|
||||
virtual bool loadFromCache();
|
||||
virtual bool saveCache();
|
||||
virtual bool discover();
|
||||
|
||||
static FFADODevice * createDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
|
||||
virtual AVC::Subunit* createSubunit(AVC::Unit& unit,
|
||||
AVC::ESubunitType type,
|
||||
AVC::subunit_t id );
|
||||
virtual AVC::Plug *createPlug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId,
|
||||
int globalId = -1 );
|
||||
|
||||
virtual int getSelectorFBValue(int id);
|
||||
virtual bool setSelectorFBValue(int id, int v);
|
||||
|
||||
virtual int getFeatureFBVolumeMinimum(int id, int channel);
|
||||
virtual int getFeatureFBVolumeMaximum(int id, int channel);
|
||||
virtual int getFeatureFBVolumeCurrent(int id, int channel);
|
||||
virtual bool setFeatureFBVolumeCurrent(int id, int channel, int v);
|
||||
|
||||
virtual int getFeatureFBLRBalanceMinimum(int id, int channel);
|
||||
virtual int getFeatureFBLRBalanceMaximum(int id, int channel);
|
||||
virtual int getFeatureFBLRBalanceCurrent(int id, int channel);
|
||||
virtual bool setFeatureFBLRBalanceCurrent(int id, int channel, int v);
|
||||
|
||||
virtual bool setProcessingFBMixerSingleCurrent(int id, int iPlugNum,
|
||||
int iAChNum, int oAChNum,
|
||||
int setting);
|
||||
virtual int getProcessingFBMixerSingleCurrent(int id, int iPlugNum,
|
||||
int iAChNum, int oAChNum);
|
||||
|
||||
virtual void showDevice();
|
||||
virtual void setVerboseLevel(int l);
|
||||
protected:
|
||||
virtual bool propagatePlugInfo();
|
||||
|
||||
virtual bool buildMixer();
|
||||
virtual bool destroyMixer();
|
||||
|
||||
virtual int getFeatureFBVolumeValue(int id, int channel, AVC::FunctionBlockCmd::EControlAttribute controlAttribute);
|
||||
virtual int getFeatureFBLRBalanceValue(int id, int channel, AVC::FunctionBlockCmd::EControlAttribute controlAttribute);
|
||||
|
||||
public:
|
||||
virtual bool serialize( std::string basePath, Util::IOSerialize& ser ) const;
|
||||
virtual bool deserialize( std::string basePath, Util::IODeserialize& deser );
|
||||
|
||||
virtual uint64_t getConfigurationId();
|
||||
virtual bool needsRediscovery();
|
||||
|
||||
std::string getCachePath();
|
||||
|
||||
protected:
|
||||
virtual uint8_t getConfigurationIdSampleRate();
|
||||
virtual uint8_t getConfigurationIdNumberOfChannel( AVC::PlugAddress::EPlugDirection ePlugDirection );
|
||||
virtual uint16_t getConfigurationIdSyncMode();
|
||||
|
||||
std::vector<int> m_supported_frequencies;
|
||||
uint64_t m_last_discovery_config_id;
|
||||
|
||||
protected:
|
||||
Mixer* m_Mixer;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob/bebob_functionblock.h"
|
||||
#include "bebob/bebob_avdevice_subunit.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
#include "bebob/bebob_avplug.h"
|
||||
#include "libieee1394/configrom.h"
|
||||
|
||||
#include "libavc/general/avc_plug_info.h"
|
||||
#include "libavc/streamformat/avc_extended_stream_format.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace AVC;
|
||||
|
||||
//////////////////////////
|
||||
|
||||
BeBoB::SubunitAudio::SubunitAudio( AVC::Unit& avDevice,
|
||||
subunit_t id )
|
||||
: AVC::SubunitAudio( avDevice, id )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::SubunitAudio::SubunitAudio()
|
||||
: AVC::SubunitAudio()
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::SubunitAudio::~SubunitAudio()
|
||||
{
|
||||
for ( FunctionBlockVector::iterator it = m_functions.begin();
|
||||
it != m_functions.end();
|
||||
++it )
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
AVC::Plug *
|
||||
BeBoB::SubunitAudio::createPlug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId )
|
||||
{
|
||||
|
||||
return new BeBoB::Plug( unit,
|
||||
subunit,
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::discover()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
|
||||
|
||||
// discover the AV/C generic part
|
||||
if ( !AVC::SubunitAudio::discover() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do the remaining BeBoB audio subunit discovery
|
||||
if ( !discoverFunctionBlocks() ) {
|
||||
debugError( "function block discovering failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::discoverConnections()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Discovering connections...\n");
|
||||
if ( !Subunit::discoverConnections() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( FunctionBlockVector::iterator it = m_functions.begin();
|
||||
it != m_functions.end();
|
||||
++it )
|
||||
{
|
||||
FunctionBlock* function = *it;
|
||||
if ( !function->discoverConnections() ) {
|
||||
debugError( "functionblock connection discovering failed ('%s')\n",
|
||||
function->getName() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char*
|
||||
BeBoB::SubunitAudio::getName()
|
||||
{
|
||||
return "BeBoB::AudioSubunit";
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::discoverFunctionBlocks()
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_NORMAL,
|
||||
"Discovering function blocks...\n");
|
||||
|
||||
if ( !discoverFunctionBlocksDo(
|
||||
ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector) )
|
||||
{
|
||||
debugError( "Could not discover function block selector\n" );
|
||||
return false;
|
||||
}
|
||||
if ( !discoverFunctionBlocksDo(
|
||||
ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature) )
|
||||
{
|
||||
debugError( "Could not discover function block feature\n" );
|
||||
return false;
|
||||
}
|
||||
if ( !discoverFunctionBlocksDo(
|
||||
ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing) )
|
||||
{
|
||||
debugError( "Could not discover function block processing\n" );
|
||||
return false;
|
||||
}
|
||||
if ( !discoverFunctionBlocksDo(
|
||||
ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec) )
|
||||
{
|
||||
debugError( "Could not discover function block codec\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// print a function block list
|
||||
#ifdef DEBUG
|
||||
if ((int)getDebugLevel() >= DEBUG_LEVEL_NORMAL) {
|
||||
|
||||
for ( FunctionBlockVector::iterator it = m_functions.begin();
|
||||
it != m_functions.end();
|
||||
++it )
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "%20s FB, type 0x%X, id=%d\n",
|
||||
(*it)->getName(),
|
||||
(*it)->getType(),
|
||||
(*it)->getId());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::discoverFunctionBlocksDo(
|
||||
ExtendedSubunitInfoCmd::EFunctionBlockType fbType )
|
||||
{
|
||||
int page = 0;
|
||||
bool cmdSuccess = false;
|
||||
bool finished = false;
|
||||
|
||||
do {
|
||||
ExtendedSubunitInfoCmd
|
||||
extSubunitInfoCmd( m_unit->get1394Service() );
|
||||
extSubunitInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
|
||||
extSubunitInfoCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
extSubunitInfoCmd.setSubunitId( getSubunitId() );
|
||||
extSubunitInfoCmd.setSubunitType( getSubunitType() );
|
||||
extSubunitInfoCmd.setVerbose( (int)getDebugLevel() );
|
||||
|
||||
extSubunitInfoCmd.m_fbType = fbType;
|
||||
extSubunitInfoCmd.m_page = page;
|
||||
|
||||
cmdSuccess = extSubunitInfoCmd.fire();
|
||||
if ( cmdSuccess
|
||||
&& ( extSubunitInfoCmd.getResponse()
|
||||
== AVCCommand::eR_Implemented ) )
|
||||
{
|
||||
for ( ExtendedSubunitInfoPageDataVector::iterator it =
|
||||
extSubunitInfoCmd.m_infoPageDatas.begin();
|
||||
cmdSuccess
|
||||
&& ( it != extSubunitInfoCmd.m_infoPageDatas.end() );
|
||||
++it )
|
||||
{
|
||||
cmdSuccess = createFunctionBlock( fbType, **it );
|
||||
}
|
||||
if ( ( extSubunitInfoCmd.m_infoPageDatas.size() != 0 )
|
||||
&& ( extSubunitInfoCmd.m_infoPageDatas.size() == 5 ) )
|
||||
{
|
||||
page++;
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
} else {
|
||||
finished = true;
|
||||
}
|
||||
} while ( cmdSuccess && !finished );
|
||||
|
||||
return cmdSuccess;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::createFunctionBlock(
|
||||
ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
|
||||
ExtendedSubunitInfoPageData& data )
|
||||
{
|
||||
FunctionBlock::ESpecialPurpose purpose
|
||||
= convertSpecialPurpose( data.m_functionBlockSpecialPupose );
|
||||
|
||||
FunctionBlock* fb = 0;
|
||||
|
||||
switch ( fbType ) {
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
|
||||
{
|
||||
fb = new FunctionBlockSelector( *this,
|
||||
data.m_functionBlockId,
|
||||
purpose,
|
||||
data.m_noOfInputPlugs,
|
||||
data.m_noOfOutputPlugs,
|
||||
(int)getDebugLevel() );
|
||||
}
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
|
||||
{
|
||||
fb = new FunctionBlockFeature( *this,
|
||||
data.m_functionBlockId,
|
||||
purpose,
|
||||
data.m_noOfInputPlugs,
|
||||
data.m_noOfOutputPlugs,
|
||||
(int)getDebugLevel() );
|
||||
}
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
|
||||
{
|
||||
switch ( data.m_functionBlockType ) {
|
||||
case ExtendedSubunitInfoCmd::ePT_EnhancedMixer:
|
||||
{
|
||||
fb = new FunctionBlockEnhancedMixer( *this,
|
||||
data.m_functionBlockId,
|
||||
purpose,
|
||||
data.m_noOfInputPlugs,
|
||||
data.m_noOfOutputPlugs,
|
||||
(int)getDebugLevel() );
|
||||
}
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::ePT_Mixer:
|
||||
case ExtendedSubunitInfoCmd::ePT_Generic:
|
||||
case ExtendedSubunitInfoCmd::ePT_UpDown:
|
||||
case ExtendedSubunitInfoCmd::ePT_DolbyProLogic:
|
||||
case ExtendedSubunitInfoCmd::ePT_3DStereoExtender:
|
||||
case ExtendedSubunitInfoCmd::ePT_Reverberation:
|
||||
case ExtendedSubunitInfoCmd::ePT_Chorus:
|
||||
case ExtendedSubunitInfoCmd::ePT_DynamicRangeCompression:
|
||||
default:
|
||||
/* It is no use to add a dummy FunctionBlockProcessing because
|
||||
then the function type is not set in FunctionBlockProcessing.
|
||||
When we try to discover the plugs attached to this function block
|
||||
it will fail. It's better just to skip them. */
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "Found a processing subfunction (type %d) which is not supported. "
|
||||
"It will be ignored.\n",
|
||||
data.m_functionBlockType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
|
||||
{
|
||||
/* It is no use to add a dummy FunctionBlockProcessing because
|
||||
then the function type is not set in FunctionBlockProcessing.
|
||||
When we try to discover the plugs attached to this function block
|
||||
it will fail. It's better just to skip them. */
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "Found a codec subfunction (type %d) which is not supported. "
|
||||
"It will be ignored.\n",
|
||||
data.m_functionBlockType);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debugError( "Unhandled function block type found\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !fb ) {
|
||||
debugError( "Could create function block\n" );
|
||||
return false;
|
||||
}
|
||||
if ( !fb->discover() ) {
|
||||
debugError( "Could not discover function block %s\n",
|
||||
fb->getName() );
|
||||
delete fb;
|
||||
return false;
|
||||
}
|
||||
m_functions.push_back( fb );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BeBoB::FunctionBlock::ESpecialPurpose
|
||||
BeBoB::SubunitAudio::convertSpecialPurpose(
|
||||
function_block_special_purpose_t specialPurpose )
|
||||
{
|
||||
FunctionBlock::ESpecialPurpose p;
|
||||
switch ( specialPurpose ) {
|
||||
case ExtendedSubunitInfoPageData::eSP_InputGain:
|
||||
p = FunctionBlock::eSP_InputGain;
|
||||
break;
|
||||
case ExtendedSubunitInfoPageData::eSP_OutputVolume:
|
||||
p = FunctionBlock::eSP_OutputVolume;
|
||||
break;
|
||||
default:
|
||||
p = FunctionBlock::eSP_NoSpecialPurpose;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
bool result = true;
|
||||
int i = 0;
|
||||
|
||||
for ( FunctionBlockVector::const_iterator it = m_functions.begin();
|
||||
it != m_functions.end();
|
||||
++it )
|
||||
{
|
||||
FunctionBlock* pFB = *it;
|
||||
std::ostringstream strstrm;
|
||||
strstrm << basePath << "FunctionBlock" << i << "/";
|
||||
|
||||
result &= pFB->serialize( strstrm.str() , ser );
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AVC::Unit& avDevice )
|
||||
{
|
||||
int i = 0;
|
||||
bool bFinished = false;
|
||||
do {
|
||||
std::ostringstream strstrm;
|
||||
strstrm << basePath << "FunctionBlock" << i << "/";
|
||||
FunctionBlock* pFB = FunctionBlock::deserialize( strstrm.str(),
|
||||
deser,
|
||||
avDevice,
|
||||
*this );
|
||||
if ( pFB ) {
|
||||
m_functions.push_back( pFB );
|
||||
i++;
|
||||
} else {
|
||||
bFinished = true;
|
||||
}
|
||||
} while ( !bFinished );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitAudio::deserializeUpdateChild( std::string basePath,
|
||||
Util::IODeserialize& deser )
|
||||
{
|
||||
bool result = true;
|
||||
int i = 0;
|
||||
|
||||
for ( FunctionBlockVector::iterator it = m_functions.begin();
|
||||
it != m_functions.end();
|
||||
++it )
|
||||
{
|
||||
std::ostringstream strstrm;
|
||||
strstrm << basePath << "FunctionBlock" << i << "/";
|
||||
|
||||
result &= (*it)->deserializeUpdate( basePath, deser );
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
BeBoB::SubunitMusic::SubunitMusic( AVC::Unit& avDevice,
|
||||
subunit_t id )
|
||||
: AVC::SubunitMusic( avDevice, id )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::SubunitMusic::SubunitMusic()
|
||||
: AVC::SubunitMusic()
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::SubunitMusic::~SubunitMusic()
|
||||
{
|
||||
}
|
||||
|
||||
AVC::Plug *
|
||||
BeBoB::SubunitMusic::createPlug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId )
|
||||
{
|
||||
|
||||
return new BeBoB::Plug( unit,
|
||||
subunit,
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitMusic::discover()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Discovering %s...\n", getName());
|
||||
|
||||
// discover the AV/C generic part
|
||||
if ( !AVC::SubunitMusic::discover() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do the remaining BeBoB music subunit discovery
|
||||
// which is nothing
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char*
|
||||
BeBoB::SubunitMusic::getName()
|
||||
{
|
||||
return "BeBoB::MusicSubunit";
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitMusic::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitMusic::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AVC::Unit& avDevice )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::SubunitMusic::deserializeUpdateChild( std::string basePath,
|
||||
Util::IODeserialize& deser )
|
||||
{
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_AVDEVICESUBUNIT_H
|
||||
#define BEBOB_AVDEVICESUBUNIT_H
|
||||
|
||||
#include "bebob/bebob_avplug.h"
|
||||
#include "bebob/bebob_functionblock.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "libavc/general/avc_extended_subunit_info.h"
|
||||
#include "libavc/avc_definitions.h"
|
||||
#include "libavc/general/avc_generic.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "libavc/general/avc_subunit.h"
|
||||
#include "libavc/musicsubunit/avc_musicsubunit.h"
|
||||
#include "libavc/audiosubunit/avc_audiosubunit.h"
|
||||
#include "libavc/general/avc_plug.h"
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
class SubunitAudio : public AVC::SubunitAudio
|
||||
{
|
||||
public:
|
||||
SubunitAudio( AVC::Unit& avDevice,
|
||||
AVC::subunit_t id );
|
||||
SubunitAudio();
|
||||
virtual ~SubunitAudio();
|
||||
|
||||
virtual bool discover();
|
||||
virtual bool discoverConnections();
|
||||
|
||||
virtual AVC::Plug *createPlug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId );
|
||||
|
||||
virtual const char* getName();
|
||||
virtual FunctionBlockVector getFunctionBlocks() { return m_functions; };
|
||||
|
||||
protected:
|
||||
bool discoverFunctionBlocks();
|
||||
bool discoverFunctionBlocksDo(
|
||||
AVC::ExtendedSubunitInfoCmd::EFunctionBlockType fbType );
|
||||
bool createFunctionBlock(
|
||||
AVC::ExtendedSubunitInfoCmd::EFunctionBlockType fbType,
|
||||
AVC::ExtendedSubunitInfoPageData& data );
|
||||
|
||||
FunctionBlock::ESpecialPurpose convertSpecialPurpose(
|
||||
AVC::function_block_special_purpose_t specialPurpose );
|
||||
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AVC::Unit& unit );
|
||||
virtual bool deserializeUpdateChild( std::string basePath,
|
||||
Util::IODeserialize& deser );
|
||||
|
||||
protected:
|
||||
FunctionBlockVector m_functions;
|
||||
};
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
class SubunitMusic : public AVC::SubunitMusic
|
||||
{
|
||||
public:
|
||||
SubunitMusic( AVC::Unit& avDevice,
|
||||
AVC::subunit_t id );
|
||||
SubunitMusic();
|
||||
virtual ~SubunitMusic();
|
||||
|
||||
virtual bool discover();
|
||||
|
||||
virtual AVC::Plug *createPlug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId );
|
||||
|
||||
virtual const char* getName();
|
||||
|
||||
protected:
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AVC::Unit& unit );
|
||||
virtual bool deserializeUpdateChild( std::string basePath,
|
||||
Util::IODeserialize& deser );
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,693 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob/bebob_avplug.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
#include "libieee1394/configrom.h"
|
||||
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
Plug::Plug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId )
|
||||
: AVC::Plug( unit,
|
||||
subunit,
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"nodeId = %d, subunitType = %d, "
|
||||
"subunitId = %d, functionBlockType = %d, "
|
||||
"functionBlockId = %d, addressType = %d, "
|
||||
"direction = %d, id = %d\n",
|
||||
unit->getConfigRom().getNodeId(),
|
||||
getSubunitType(),
|
||||
getSubunitId(),
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId );
|
||||
}
|
||||
|
||||
Plug::Plug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId,
|
||||
int globalId )
|
||||
: AVC::Plug( unit,
|
||||
subunit,
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId,
|
||||
globalId )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"nodeId = %d, subunitType = %d, "
|
||||
"subunitId = %d, functionBlockType = %d, "
|
||||
"functionBlockId = %d, addressType = %d, "
|
||||
"direction = %d, id = %d\n",
|
||||
unit->getConfigRom().getNodeId(),
|
||||
getSubunitType(),
|
||||
getSubunitId(),
|
||||
functionBlockType,
|
||||
functionBlockId,
|
||||
plugAddressType,
|
||||
plugDirection,
|
||||
plugId );
|
||||
}
|
||||
|
||||
Plug::Plug( const Plug& rhs )
|
||||
: AVC::Plug( rhs )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Plug::Plug()
|
||||
: AVC::Plug()
|
||||
{
|
||||
}
|
||||
|
||||
Plug::~Plug()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discover()
|
||||
{
|
||||
if ( !discoverPlugType() ) {
|
||||
debugError( "discover: Could not discover plug type (%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverName() ) {
|
||||
debugError( "Could not discover name (%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverNoOfChannels() ) {
|
||||
debugError( "Could not discover number of channels "
|
||||
"(%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverChannelPosition() ) {
|
||||
debugError( "Could not discover channel positions "
|
||||
"(%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverChannelName() ) {
|
||||
debugError( "Could not discover channel name "
|
||||
"(%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverClusterInfo() ) {
|
||||
debugError( "Could not discover channel name "
|
||||
"(%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverStreamFormat() ) {
|
||||
debugError( "Could not discover stream format "
|
||||
"(%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverSupportedStreamFormats() ) {
|
||||
debugError( "Could not discover supported stream formats "
|
||||
"(%d,%d,%d,%d,%d)\n",
|
||||
m_unit->getConfigRom().getNodeId(), getSubunitType(), getSubunitId(), m_direction, m_id );
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_unit->getPlugManager().addPlug( *this );
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverConnections()
|
||||
{
|
||||
return discoverConnectionsInput() && discoverConnectionsOutput();
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverPlugType()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_PlugType );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "plug type command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_infoPlugType = eAPT_Unknown;
|
||||
|
||||
if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Implemented ) {
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugType )
|
||||
{
|
||||
plug_type_t plugType = infoType->m_plugType->m_plugType;
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"plug %d is of type %d (%s)\n",
|
||||
m_id,
|
||||
plugType,
|
||||
extendedPlugInfoPlugTypeToString( plugType ) );
|
||||
switch ( plugType ) {
|
||||
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_IsoStream:
|
||||
m_infoPlugType = eAPT_IsoStream;
|
||||
break;
|
||||
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_AsyncStream:
|
||||
m_infoPlugType = eAPT_AsyncStream;
|
||||
break;
|
||||
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Midi:
|
||||
m_infoPlugType = eAPT_Midi;
|
||||
break;
|
||||
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Sync:
|
||||
m_infoPlugType = eAPT_Sync;
|
||||
break;
|
||||
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Analog:
|
||||
m_infoPlugType = eAPT_Analog;
|
||||
break;
|
||||
case ExtendedPlugInfoPlugTypeSpecificData::eEPIPT_Digital:
|
||||
m_infoPlugType = eAPT_Digital;
|
||||
break;
|
||||
default:
|
||||
m_infoPlugType = eAPT_Unknown;
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugError( "Plug does not implement extended plug info plug "
|
||||
"type info command\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverName()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_PlugName );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "name command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugName )
|
||||
{
|
||||
std::string name =
|
||||
infoType->m_plugName->m_name;
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"plug %d has name '%s'\n",
|
||||
m_id,
|
||||
name.c_str() );
|
||||
|
||||
m_name = name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverNoOfChannels()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
//extPlugInfoCmd.setVerbose( true );
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_NoOfChannels );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "number of channels command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugNrOfChns )
|
||||
{
|
||||
nr_of_channels_t nrOfChannels
|
||||
= infoType->m_plugNrOfChns->m_nrOfChannels;
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"plug %d has %d channels\n",
|
||||
m_id,
|
||||
nrOfChannels );
|
||||
|
||||
m_nrOfChannels = nrOfChannels;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverChannelPosition()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_ChannelPosition );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "channel position command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugChannelPosition )
|
||||
{
|
||||
if ( !copyClusterInfo( *( infoType->m_plugChannelPosition ) ) ) {
|
||||
debugError( "Could not copy channel position "
|
||||
"information\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"plug %d: channel position information "
|
||||
"retrieved\n",
|
||||
m_id );
|
||||
|
||||
debugOutputClusterInfos( DEBUG_LEVEL_VERBOSE );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::copyClusterInfo(ExtendedPlugInfoPlugChannelPositionSpecificData&
|
||||
channelPositionData )
|
||||
{
|
||||
int index = 1;
|
||||
for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfoVector::const_iterator it
|
||||
= channelPositionData.m_clusterInfos.begin();
|
||||
it != channelPositionData.m_clusterInfos.end();
|
||||
++it )
|
||||
{
|
||||
const ExtendedPlugInfoPlugChannelPositionSpecificData::ClusterInfo*
|
||||
extPlugSpClusterInfo = &( *it );
|
||||
|
||||
ClusterInfo clusterInfo;
|
||||
clusterInfo.m_nrOfChannels = extPlugSpClusterInfo->m_nrOfChannels;
|
||||
clusterInfo.m_index = index;
|
||||
index++;
|
||||
|
||||
for ( ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfoVector::const_iterator cit
|
||||
= extPlugSpClusterInfo->m_channelInfos.begin();
|
||||
cit != extPlugSpClusterInfo->m_channelInfos.end();
|
||||
++cit )
|
||||
{
|
||||
const ExtendedPlugInfoPlugChannelPositionSpecificData::ChannelInfo*
|
||||
extPlugSpChannelInfo = &( *cit );
|
||||
|
||||
ChannelInfo channelInfo;
|
||||
channelInfo.m_streamPosition =
|
||||
extPlugSpChannelInfo->m_streamPosition-1;
|
||||
// FIXME: this can only become a mess with the two meanings
|
||||
// of the location parameter. the audio style meaning
|
||||
// starts from 1, the midi style meaning from 0
|
||||
// lucky for us we recalculate this for the midi channels
|
||||
// and don't use this value.
|
||||
channelInfo.m_location =
|
||||
extPlugSpChannelInfo->m_location;
|
||||
|
||||
clusterInfo.m_channelInfos.push_back( channelInfo );
|
||||
}
|
||||
m_clusterInfos.push_back( clusterInfo );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverChannelName()
|
||||
{
|
||||
for ( ClusterInfoVector::iterator clit = m_clusterInfos.begin();
|
||||
clit != m_clusterInfos.end();
|
||||
++clit )
|
||||
{
|
||||
ClusterInfo* clitInfo = &*clit;
|
||||
|
||||
for ( ChannelInfoVector::iterator pit = clitInfo->m_channelInfos.begin();
|
||||
pit != clitInfo->m_channelInfos.end();
|
||||
++pit )
|
||||
{
|
||||
ChannelInfo* channelInfo = &*pit;
|
||||
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_ChannelName );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType =
|
||||
extPlugInfoCmd.getInfoType();
|
||||
if ( infoType ) {
|
||||
infoType->m_plugChannelName->m_streamPosition =
|
||||
channelInfo->m_streamPosition + 1;
|
||||
}
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "channel name command failed\n" );
|
||||
return false;
|
||||
}
|
||||
infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugChannelName )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"plug %d stream "
|
||||
"position %d: channel name = %s\n",
|
||||
m_id,
|
||||
channelInfo->m_streamPosition,
|
||||
infoType->m_plugChannelName->m_plugChannelName.c_str() );
|
||||
channelInfo->m_name =
|
||||
infoType->m_plugChannelName->m_plugChannelName;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverClusterInfo()
|
||||
{
|
||||
if ( m_infoPlugType == eAPT_Sync )
|
||||
{
|
||||
// If the plug is of type sync it is either a normal 2 channel
|
||||
// stream (not compound stream) or it is a compound stream
|
||||
// with exactly one cluster. This depends on the
|
||||
// extended stream format command version which is used.
|
||||
// We are not interested in this plug so we skip it.
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"%s plug %d is of type sync -> skip\n",
|
||||
getName(),
|
||||
m_id );
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( ClusterInfoVector::iterator clit = m_clusterInfos.begin();
|
||||
clit != m_clusterInfos.end();
|
||||
++clit )
|
||||
{
|
||||
ClusterInfo* clusterInfo = &*clit;
|
||||
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_ClusterInfo );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
extPlugInfoCmd.getInfoType()->m_plugClusterInfo->m_clusterIndex =
|
||||
clusterInfo->m_index;
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "cluster info command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugClusterInfo )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"%s plug %d: cluster index = %d, "
|
||||
"portType %s, cluster name = %s\n",
|
||||
getName(),
|
||||
m_id,
|
||||
infoType->m_plugClusterInfo->m_clusterIndex,
|
||||
extendedPlugInfoClusterInfoPortTypeToString(
|
||||
infoType->m_plugClusterInfo->m_portType ),
|
||||
infoType->m_plugClusterInfo->m_clusterName.c_str() );
|
||||
|
||||
clusterInfo->m_portType = infoType->m_plugClusterInfo->m_portType;
|
||||
clusterInfo->m_name = infoType->m_plugClusterInfo->m_clusterName;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverConnectionsInput()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_PlugInput );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "plug type command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Rejected ) {
|
||||
// Plugs does not like to be asked about connections
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' rejects "
|
||||
"connections command\n",
|
||||
getName() );
|
||||
return true;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugInput )
|
||||
{
|
||||
PlugAddressSpecificData* plugAddress
|
||||
= infoType->m_plugInput->m_plugAddress;
|
||||
|
||||
if ( plugAddress->m_addressMode ==
|
||||
PlugAddressSpecificData::ePAM_Undefined )
|
||||
{
|
||||
// This plug has no input connection
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !discoverConnectionsFromSpecificData( eAPD_Input,
|
||||
plugAddress,
|
||||
m_inputConnections ) )
|
||||
{
|
||||
debugWarning( "Could not discover connections for plug '%s'\n",
|
||||
getName() );
|
||||
}
|
||||
} else {
|
||||
debugError( "no valid info type for plug '%s'\n", getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Plug::discoverConnectionsOutput()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd = setPlugAddrToPlugInfoCmd();
|
||||
ExtendedPlugInfoInfoType extendedPlugInfoInfoType(
|
||||
ExtendedPlugInfoInfoType::eIT_PlugOutput );
|
||||
extendedPlugInfoInfoType.initialize();
|
||||
extPlugInfoCmd.setInfoType( extendedPlugInfoInfoType );
|
||||
extPlugInfoCmd.setVerbose( getDebugLevel() );
|
||||
|
||||
if ( !extPlugInfoCmd.fire() ) {
|
||||
debugError( "plug type command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( extPlugInfoCmd.getResponse() == AVCCommand::eR_Rejected ) {
|
||||
// Plugs does not like to be asked about connections
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Plug '%s' rejects "
|
||||
"connections command\n",
|
||||
getName() );
|
||||
return true;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoInfoType* infoType = extPlugInfoCmd.getInfoType();
|
||||
if ( infoType
|
||||
&& infoType->m_plugOutput )
|
||||
{
|
||||
if ( infoType->m_plugOutput->m_nrOfOutputPlugs
|
||||
!= infoType->m_plugOutput->m_outputPlugAddresses.size() )
|
||||
{
|
||||
debugError( "number of output plugs (%d) disagree with "
|
||||
"number of elements in plug address vector (%zd)\n",
|
||||
infoType->m_plugOutput->m_nrOfOutputPlugs,
|
||||
infoType->m_plugOutput->m_outputPlugAddresses.size());
|
||||
}
|
||||
|
||||
if ( infoType->m_plugOutput->m_nrOfOutputPlugs == 0 ) {
|
||||
// This plug has no output connections
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0;
|
||||
i < infoType->m_plugOutput->m_outputPlugAddresses.size();
|
||||
++i )
|
||||
{
|
||||
PlugAddressSpecificData* plugAddress
|
||||
= infoType->m_plugOutput->m_outputPlugAddresses[i];
|
||||
|
||||
if ( !discoverConnectionsFromSpecificData( eAPD_Output,
|
||||
plugAddress,
|
||||
m_outputConnections ) )
|
||||
{
|
||||
debugWarning( "Could not discover connections for "
|
||||
"plug '%s'\n", getName() );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugError( "no valid info type for plug '%s'\n", getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ExtendedPlugInfoCmd
|
||||
Plug::setPlugAddrToPlugInfoCmd()
|
||||
{
|
||||
ExtendedPlugInfoCmd extPlugInfoCmd( m_unit->get1394Service() );
|
||||
|
||||
switch( getSubunitType() ) {
|
||||
case eST_Unit:
|
||||
{
|
||||
UnitPlugAddress::EPlugType ePlugType =
|
||||
UnitPlugAddress::ePT_Unknown;
|
||||
switch ( m_addressType ) {
|
||||
case eAPA_PCR:
|
||||
ePlugType = UnitPlugAddress::ePT_PCR;
|
||||
break;
|
||||
case eAPA_ExternalPlug:
|
||||
ePlugType = UnitPlugAddress::ePT_ExternalPlug;
|
||||
break;
|
||||
case eAPA_AsynchronousPlug:
|
||||
ePlugType = UnitPlugAddress::ePT_AsynchronousPlug;
|
||||
break;
|
||||
default:
|
||||
ePlugType = UnitPlugAddress::ePT_Unknown;
|
||||
}
|
||||
UnitPlugAddress unitPlugAddress( ePlugType,
|
||||
m_id );
|
||||
extPlugInfoCmd.setPlugAddress(
|
||||
PlugAddress( convertPlugDirection( getPlugDirection() ),
|
||||
PlugAddress::ePAM_Unit,
|
||||
unitPlugAddress ) );
|
||||
}
|
||||
break;
|
||||
case eST_Music:
|
||||
case eST_Audio:
|
||||
{
|
||||
switch( m_addressType ) {
|
||||
case eAPA_SubunitPlug:
|
||||
{
|
||||
SubunitPlugAddress subunitPlugAddress( m_id );
|
||||
extPlugInfoCmd.setPlugAddress(
|
||||
PlugAddress(
|
||||
convertPlugDirection( getPlugDirection() ),
|
||||
PlugAddress::ePAM_Subunit,
|
||||
subunitPlugAddress ) );
|
||||
}
|
||||
break;
|
||||
case eAPA_FunctionBlockPlug:
|
||||
{
|
||||
FunctionBlockPlugAddress functionBlockPlugAddress(
|
||||
m_functionBlockType,
|
||||
m_functionBlockId,
|
||||
m_id );
|
||||
extPlugInfoCmd.setPlugAddress(
|
||||
PlugAddress(
|
||||
convertPlugDirection( getPlugDirection() ),
|
||||
PlugAddress::ePAM_FunctionBlock,
|
||||
functionBlockPlugAddress ) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
extPlugInfoCmd.setPlugAddress(PlugAddress());
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debugError( "Unknown subunit type\n" );
|
||||
}
|
||||
|
||||
extPlugInfoCmd.setNodeId( m_unit->getConfigRom().getNodeId() );
|
||||
extPlugInfoCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
extPlugInfoCmd.setSubunitId( getSubunitId() );
|
||||
extPlugInfoCmd.setSubunitType( getSubunitType() );
|
||||
|
||||
return extPlugInfoCmd;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_AVPLUG_H
|
||||
#define BEBOB_AVPLUG_H
|
||||
|
||||
#include "libavc/ccm/avc_signal_source.h"
|
||||
#include "libavc/streamformat/avc_extended_stream_format.h"
|
||||
#include "libavc/general/avc_extended_plug_info.h"
|
||||
#include "libavc/general/avc_extended_cmd_generic.h"
|
||||
#include "libavc/avc_definitions.h"
|
||||
#include "libavc/general/avc_generic.h"
|
||||
#include "libavc/general/avc_plug.h"
|
||||
|
||||
#include "libutil/serialize.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
class Ieee1394Service;
|
||||
class ConfigRom;
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
class AvDevice;
|
||||
|
||||
class Plug : public AVC::Plug {
|
||||
public:
|
||||
|
||||
// \todo This constructors sucks. too many parameters. fix it.
|
||||
Plug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId );
|
||||
Plug( AVC::Unit* unit,
|
||||
AVC::Subunit* subunit,
|
||||
AVC::function_block_type_t functionBlockType,
|
||||
AVC::function_block_type_t functionBlockId,
|
||||
AVC::Plug::EPlugAddressType plugAddressType,
|
||||
AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugId,
|
||||
int globalId );
|
||||
Plug( const Plug& rhs );
|
||||
virtual ~Plug();
|
||||
|
||||
bool discover();
|
||||
bool discoverConnections();
|
||||
|
||||
public:
|
||||
|
||||
protected:
|
||||
Plug();
|
||||
|
||||
bool discoverPlugType();
|
||||
bool discoverName();
|
||||
bool discoverNoOfChannels();
|
||||
bool discoverChannelPosition();
|
||||
bool discoverChannelName();
|
||||
bool discoverClusterInfo();
|
||||
bool discoverConnectionsInput();
|
||||
bool discoverConnectionsOutput();
|
||||
|
||||
private:
|
||||
bool copyClusterInfo(AVC::ExtendedPlugInfoPlugChannelPositionSpecificData&
|
||||
channelPositionData );
|
||||
AVC::ExtendedPlugInfoCmd setPlugAddrToPlugInfoCmd();
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BEBOB_AVPLUG_H
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob_dl_bcd.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace BeBoB {
|
||||
enum {
|
||||
BCDMagic = 0x446f4362,
|
||||
};
|
||||
|
||||
// XXX not very nice tool box function?
|
||||
std::string makeString( fb_octlet_t v )
|
||||
{
|
||||
std::string s;
|
||||
|
||||
for ( unsigned int i=0; i<sizeof( v ); ++i ) {
|
||||
s += reinterpret_cast<char*> ( &v )[i];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string makeDate( fb_octlet_t v )
|
||||
{
|
||||
std::string s;
|
||||
char* vc = reinterpret_cast<char*> ( &v );
|
||||
|
||||
s += vc[6];
|
||||
s += vc[7];
|
||||
s += '.';
|
||||
s += vc[4];
|
||||
s += vc[5];
|
||||
s += '.';
|
||||
s += vc[0];
|
||||
s += vc[1];
|
||||
s += vc[2];
|
||||
s += vc[3];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string makeTime( fb_octlet_t v )
|
||||
{
|
||||
std::string s;
|
||||
char* vc = reinterpret_cast<char*>( &v );
|
||||
|
||||
s += vc[0];
|
||||
s += vc[1];
|
||||
s += ':';
|
||||
s += vc[2];
|
||||
s += vc[3];
|
||||
s += ':';
|
||||
s += vc[4];
|
||||
s += vc[5];
|
||||
s += vc[6];
|
||||
s += vc[7];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
enum {
|
||||
BCDFileVersionOffset = 0x28,
|
||||
|
||||
V0HeaderCRCOffset = 0x2c,
|
||||
V0HeaderSize = 0x60,
|
||||
|
||||
V1HeaderCRC0ffset = 0x2c,
|
||||
V1HeaderSize = 0x70,
|
||||
};
|
||||
|
||||
IMPL_DEBUG_MODULE( BCD, BCD, DEBUG_LEVEL_NORMAL );
|
||||
};
|
||||
|
||||
BeBoB::BCD::BCD( std::string filename )
|
||||
: m_file( 0 )
|
||||
, m_filename( filename )
|
||||
, m_bcd_version( -1 )
|
||||
, m_softwareDate( 0 )
|
||||
, m_softwareTime( 0 )
|
||||
, m_softwareId( 0 )
|
||||
, m_softwareVersion( 0 )
|
||||
, m_hardwareId( 0 )
|
||||
, m_vendorOUI( 0 )
|
||||
, m_imageBaseAddress( 0 )
|
||||
, m_imageLength( 0 )
|
||||
, m_imageOffset( 0 )
|
||||
, m_imageCRC( 0 )
|
||||
, m_cneLength( 0 )
|
||||
, m_cneOffset( 0 )
|
||||
, m_cneCRC( 0 )
|
||||
{
|
||||
initCRC32Table();
|
||||
}
|
||||
|
||||
BeBoB::BCD::~BCD()
|
||||
{
|
||||
if ( m_file ) {
|
||||
fclose( m_file );
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BCD::parse()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
m_file = fopen( m_filename.c_str(), "r" );
|
||||
if ( !m_file ) {
|
||||
debugError( "parse: Could not open file '%s'\n",
|
||||
m_filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_quadlet_t identifier;
|
||||
size_t bytes_read = fread( &identifier, 1, sizeof( identifier ), m_file );
|
||||
if ( bytes_read != sizeof( identifier ) ) {
|
||||
debugError( "parse: 4 bytes read failed at position 0\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( identifier != BCDMagic ) {
|
||||
debugError( "parse: File has not BCD header magic, 0x%08x expected, "
|
||||
"0x%08x found\n", BCDMagic, identifier );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( fseek( m_file, BCDFileVersionOffset, SEEK_SET ) == -1 ) {
|
||||
debugError( "parse: fseek failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_read = fread( &m_bcd_version, 1, sizeof( fb_quadlet_t ), m_file );
|
||||
if ( bytes_read != sizeof( fb_quadlet_t ) ) {
|
||||
debugError( "parse: %zd bytes read at position %d failed\n",
|
||||
sizeof( fb_quadlet_t ),
|
||||
BCDFileVersionOffset );
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int headerSize = 0;
|
||||
unsigned int crcOffset = 0;
|
||||
switch( m_bcd_version ) {
|
||||
case 0:
|
||||
headerSize = V0HeaderSize;
|
||||
crcOffset = V0HeaderCRCOffset;
|
||||
break;
|
||||
case 1:
|
||||
headerSize = V1HeaderSize;
|
||||
crcOffset = V1HeaderCRC0ffset;
|
||||
break;
|
||||
default:
|
||||
debugError( "parse: Unknown BCD file version %d found\n",
|
||||
m_bcd_version );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !checkHeaderCRC( crcOffset, headerSize ) ) {
|
||||
debugError( "parse: Header CRC check failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !readHeaderInfo() ) {
|
||||
debugError( "parse: Could not read all header info\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BCD::readHeaderInfo()
|
||||
{
|
||||
if ( !read( 0x08, &m_softwareDate ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x10, &m_softwareTime ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x18, &m_softwareId ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x1c, &m_softwareVersion ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x20, &m_hardwareId ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x24, &m_vendorOUI ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x30, &m_imageOffset ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x34, &m_imageBaseAddress ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x38, &m_imageLength ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x3c, &m_imageCRC ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x50, &m_cneOffset ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x58, &m_cneLength ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( !read( 0x5c, &m_cneCRC ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BCD::read( int addr, fb_quadlet_t* q )
|
||||
{
|
||||
if ( std::fseek( m_file, addr, SEEK_SET ) == -1 ) {
|
||||
debugError( "read: seek to position 0x%08x failed\n", addr );
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t bytes_read = std::fread( q, 1, sizeof( *q ), m_file );
|
||||
if ( bytes_read != sizeof( *q ) ) {
|
||||
debugError( "read: %zd byte read failed at position 0x%08x\n",
|
||||
sizeof( *q ), addr );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BCD::read( int addr, fb_octlet_t* o )
|
||||
{
|
||||
if ( std::fseek( m_file, addr, SEEK_SET ) == -1 ) {
|
||||
debugError( "read: seek to position 0x%08x failed\n", addr );
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t bytes_read = std::fread( o, 1, sizeof( *o ), m_file );
|
||||
if ( bytes_read != sizeof( *o ) ) {
|
||||
debugError( "read: %zd byte read failed at position 0x%08x\n",
|
||||
sizeof( *o ), addr );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BCD::read( int addr, unsigned char* b, size_t len )
|
||||
{
|
||||
if ( std::fseek( m_file, addr, SEEK_SET ) == -1 ) {
|
||||
debugError( "read: seek to position 0x%08x failed\n", addr );
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t bytes_read = std::fread( b, 1, len, m_file );
|
||||
if ( bytes_read != len ) {
|
||||
debugError( "read: %zd byte read failed at position 0x%08x\n",
|
||||
len, addr );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BeBoB::BCD::initCRC32Table()
|
||||
{
|
||||
unsigned long polynomial = 0x04c11db7;
|
||||
|
||||
for ( int i = 0; i <= 0xff; ++i ) {
|
||||
crc32_table[i] = reflect( i, 8 ) << 24;
|
||||
for ( int j = 0; j < 8; ++j ) {
|
||||
crc32_table[i] =
|
||||
(crc32_table[i] << 1)
|
||||
^ (crc32_table[i] & (1 << 31) ? polynomial : 0);
|
||||
}
|
||||
crc32_table[i] = reflect( crc32_table[i], 32 );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long
|
||||
BeBoB::BCD::reflect( unsigned long ref, char ch )
|
||||
{
|
||||
unsigned long value = 0;
|
||||
|
||||
for ( int i = 1; i < (ch + 1); ++i ) {
|
||||
if(ref & 1) {
|
||||
value |= 1 << (ch - i);
|
||||
}
|
||||
ref >>= 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
BeBoB::BCD::getCRC( unsigned char* text, size_t len )
|
||||
{
|
||||
unsigned long crc = 0xffffffff;
|
||||
unsigned char* buffer;
|
||||
|
||||
buffer = text;
|
||||
while ( len-- ) {
|
||||
crc = (crc >> 8) ^ crc32_table[(crc & 0xff) ^ *buffer++];
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BCD::checkHeaderCRC( unsigned int crcOffset, unsigned int headerSize )
|
||||
{
|
||||
fb_quadlet_t headerCRC;
|
||||
if ( !read( crcOffset, &headerCRC ) ) {
|
||||
debugError( "checkHeaderCRC: Could not read header CRC\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
const int headerLength = headerSize;
|
||||
unsigned char buf[headerLength];
|
||||
if ( !read( 0x00, buf, headerLength ) ) {
|
||||
debugError( "checkHeaderCRC: Could not read complete header from file\n" );
|
||||
return false;
|
||||
}
|
||||
buf[crcOffset+0] = 0x00;
|
||||
buf[crcOffset+1] = 0x00;
|
||||
buf[crcOffset+2] = 0x00;
|
||||
buf[crcOffset+3] = 0x00;
|
||||
|
||||
fb_quadlet_t calcCRC = getCRC( buf, headerLength );
|
||||
if ( headerCRC != calcCRC ) {
|
||||
debugError( "checkHeaderCRC: CRC check failed, 0x%08x expected, "
|
||||
"0x%08x calculated\n", headerCRC, calcCRC );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BeBoB::BCD::displayInfo()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
printf( "BCD Info\n" );
|
||||
printf( "\tBCD File Version\t%d\n", m_bcd_version );
|
||||
printf( "\tSoftware Date:\t\t%s, %s\n",
|
||||
makeDate( m_softwareDate ).c_str(),
|
||||
makeTime( m_softwareTime ).c_str() );
|
||||
printf( "\tSoftware Version:\t0x%08x\n", m_softwareVersion );
|
||||
printf( "\tSoftware Id:\t\t0x%08x\n", m_softwareId );
|
||||
printf( "\tHardware ID:\t\t0x%08x\n", m_hardwareId );
|
||||
printf( "\tVendor OUI:\t\t0x%08x\n", m_vendorOUI );
|
||||
printf( "\tImage Offset:\t\t0x%08x\n", m_imageOffset );
|
||||
printf( "\tImage Base Address:\t0x%08x\n", m_imageBaseAddress );
|
||||
printf( "\tImage Length:\t\t0x%08x\n", m_imageLength );
|
||||
printf( "\tImage CRC:\t\t0x%08x\n", m_imageCRC );
|
||||
printf( "\tCNE Length:\t\t0x%08x\n", m_cneLength );
|
||||
printf( "\tCNE Offset:\t\t0x%08x\n", m_cneOffset );
|
||||
printf( "\tCNE CRC:\t\t0x%08x\n", m_cneCRC );
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_DL_BCD_H
|
||||
#define BEBOB_DL_BCD_H
|
||||
|
||||
#include "fbtypes.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
class BCD {
|
||||
public:
|
||||
BCD( std::string filename );
|
||||
~BCD();
|
||||
|
||||
bool parse();
|
||||
|
||||
fb_octlet_t getSoftwareDate() const
|
||||
{ return m_softwareDate; }
|
||||
fb_octlet_t getSoftwareTime() const
|
||||
{ return m_softwareTime; }
|
||||
fb_quadlet_t getSoftwareId() const
|
||||
{ return m_softwareId; }
|
||||
fb_quadlet_t getSoftwareVersion() const
|
||||
{ return m_softwareVersion; }
|
||||
fb_quadlet_t getHardwareId() const
|
||||
{ return m_hardwareId; }
|
||||
fb_quadlet_t getVendorOUI() const
|
||||
{ return m_vendorOUI; }
|
||||
|
||||
fb_quadlet_t getImageBaseAddress() const
|
||||
{ return m_imageBaseAddress; }
|
||||
fb_quadlet_t getImageOffset() const
|
||||
{ return m_imageOffset; }
|
||||
fb_quadlet_t getImageLength() const
|
||||
{ return m_imageLength; }
|
||||
fb_quadlet_t getImageCRC() const
|
||||
{ return m_imageCRC; }
|
||||
|
||||
fb_quadlet_t getCnEOffset() const
|
||||
{ return m_cneOffset; }
|
||||
fb_quadlet_t getCnELength() const
|
||||
{ return m_cneLength; }
|
||||
fb_quadlet_t getCnECRC() const
|
||||
{ return m_cneCRC; }
|
||||
|
||||
bool read( int addr, fb_quadlet_t* q );
|
||||
bool read( int addr, fb_octlet_t* o );
|
||||
bool read( int addr, unsigned char* b, size_t len );
|
||||
|
||||
void displayInfo();
|
||||
|
||||
protected:
|
||||
unsigned long crc32_table[256];
|
||||
void initCRC32Table();
|
||||
unsigned long reflect(unsigned long ref, char ch);
|
||||
unsigned int getCRC(unsigned char* text, size_t len);
|
||||
bool checkHeaderCRC( unsigned int crcOffset,
|
||||
unsigned int headerSize );
|
||||
bool readHeaderInfo();
|
||||
protected:
|
||||
std::FILE* m_file;
|
||||
std::string m_filename;
|
||||
fb_quadlet_t m_bcd_version;
|
||||
|
||||
fb_octlet_t m_softwareDate;
|
||||
fb_octlet_t m_softwareTime;
|
||||
fb_quadlet_t m_softwareId;
|
||||
fb_quadlet_t m_softwareVersion;
|
||||
fb_quadlet_t m_hardwareId;
|
||||
fb_quadlet_t m_vendorOUI;
|
||||
|
||||
|
||||
fb_quadlet_t m_imageBaseAddress;
|
||||
fb_quadlet_t m_imageLength;
|
||||
fb_quadlet_t m_imageOffset;
|
||||
fb_quadlet_t m_imageCRC;
|
||||
|
||||
fb_quadlet_t m_cneLength;
|
||||
fb_quadlet_t m_cneOffset;
|
||||
fb_quadlet_t m_cneCRC;
|
||||
|
||||
|
||||
|
||||
DECLARE_DEBUG_MODULE;
|
||||
};
|
||||
|
||||
std::string makeString( fb_octlet_t v );
|
||||
std::string makeDate( fb_octlet_t v );
|
||||
std::string makeTime( fb_octlet_t v );
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob/bebob_dl_codes.h"
|
||||
#include "bebob/bebob_dl_bcd.h"
|
||||
|
||||
unsigned short BeBoB::CommandCodes::m_gCommandId = 0;
|
||||
|
||||
BeBoB::CommandCodes::CommandCodes( fb_quadlet_t protocolVersion,
|
||||
fb_byte_t commandCode,
|
||||
size_t msgSize,
|
||||
fb_byte_t operandSizeRequest,
|
||||
fb_byte_t operandSizeRespone )
|
||||
: m_commandId( m_gCommandId++ )
|
||||
, m_protocolVersion( protocolVersion )
|
||||
, m_commandCode( commandCode )
|
||||
, m_msgSize( msgSize )
|
||||
, m_operandSizeRequest( operandSizeRequest )
|
||||
, m_operandSizeResponse( operandSizeRespone )
|
||||
, m_resp_protocolVersion( 0 )
|
||||
, m_resp_commandId( 0 )
|
||||
, m_resp_commandCode( 0 )
|
||||
, m_resp_operandSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodes::~CommandCodes()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodes::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
byte_t tmp;
|
||||
|
||||
bool result = se.write( m_protocolVersion, "CommandCodes: protocol version" );
|
||||
tmp = m_commandId & 0xff;
|
||||
result &= se.write( tmp, "CommandCodes: command id low" );
|
||||
tmp = m_commandId >> 8;
|
||||
result &= se.write( tmp, "CommandCodes: command id high" );
|
||||
result &= se.write( m_commandCode, "CommandCodes: command code" );
|
||||
result &= se.write( m_operandSizeRequest, "CommandCodes: request operand size" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodes::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result = de.read( &m_resp_protocolVersion );
|
||||
fb_byte_t tmp;
|
||||
result &= de.read( &tmp );
|
||||
m_resp_commandId = tmp;
|
||||
result &= de.read( &tmp );
|
||||
m_resp_commandId |= tmp << 8;
|
||||
result &= de.read( &m_resp_commandCode );
|
||||
result &= de.read( &m_resp_operandSize );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t
|
||||
BeBoB::CommandCodes::getMaxSize()
|
||||
{
|
||||
return 2 * sizeof( fb_quadlet_t ) + m_msgSize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesReset::CommandCodesReset( fb_quadlet_t protocolVersion,
|
||||
EStartMode startMode )
|
||||
: CommandCodes( protocolVersion, eCmdC_Reset, sizeof( m_startMode ), 1, 0 )
|
||||
, m_startMode( startMode )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesReset::~CommandCodesReset()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesReset::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result = CommandCodes::serialize( se );
|
||||
result &= se.write( m_startMode, "CommandCodesReset: boot mode" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesReset::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
return CommandCodes::deserialize( de );
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesProgramGUID::CommandCodesProgramGUID(
|
||||
fb_quadlet_t protocolVersion,
|
||||
fb_octlet_t guid )
|
||||
: CommandCodes( protocolVersion, eCmdC_ProgramGUID, sizeof( m_guid ), 2, 0 )
|
||||
, m_guid( guid )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesProgramGUID::~CommandCodesProgramGUID()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesProgramGUID::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result = CommandCodes::serialize( se );
|
||||
fb_quadlet_t tmp = m_guid >> 32;
|
||||
result &= se.write( tmp, "CommandCodesProgramGUID: GUID (high)" );
|
||||
tmp = m_guid & 0xffffffff;
|
||||
result &= se.write( tmp, "CommandCodesProgramGUID: GUID (low)" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesProgramGUID::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
return CommandCodes::deserialize( de );
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesDownloadStart::CommandCodesDownloadStart(
|
||||
fb_quadlet_t protocolVersion,
|
||||
EObject object )
|
||||
: CommandCodes( protocolVersion, eCmdC_DownloadStart, 10*4, 10, 1 )
|
||||
, m_object( object )
|
||||
, m_date( 0 )
|
||||
, m_time( 0 )
|
||||
, m_id( 0 )
|
||||
, m_version( 0 )
|
||||
, m_address( 0 )
|
||||
, m_length( 0 )
|
||||
, m_crc( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesDownloadStart::~CommandCodesDownloadStart()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesDownloadStart::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result = CommandCodes::serialize( se );
|
||||
|
||||
result &= se.write( m_object, "CommandCodesDownloadStart: object" );
|
||||
for ( unsigned int i = 0; i < sizeof( m_date ); ++i ) {
|
||||
fb_byte_t* tmp = ( fb_byte_t* )( &m_date );
|
||||
result &= se.write( tmp[i], "CommandCodesDownloadStart: date" );
|
||||
}
|
||||
for ( unsigned int i = 0; i < sizeof( m_date ); ++i ) {
|
||||
fb_byte_t* tmp = ( fb_byte_t* )( &m_time );
|
||||
result &= se.write( tmp[i], "CommandCodesDownloadStart: time" );
|
||||
}
|
||||
result &= se.write( m_id, "CommandCodesDownloadStart: id" );
|
||||
result &= se.write( m_version, "CommandCodesDownloadStart: version" );
|
||||
result &= se.write( m_address, "CommandCodesDownloadStart: address" );
|
||||
result &= se.write( m_length, "CommandCodesDownloadStart: length" );
|
||||
result &= se.write( m_crc, "CommandCodesDownloadStart: crc" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesDownloadStart::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result = CommandCodes::deserialize( de );
|
||||
result &= de.read( reinterpret_cast<fb_quadlet_t*>( &m_resp_max_block_size ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesDownloadBlock::CommandCodesDownloadBlock(
|
||||
fb_quadlet_t protocolVersion )
|
||||
: CommandCodes( protocolVersion,
|
||||
eCmdC_DownloadBlock,
|
||||
12,
|
||||
3,
|
||||
2 )
|
||||
, m_seqNumber( 0 )
|
||||
, m_address ( 0 )
|
||||
, m_resp_seqNumber( 0 )
|
||||
, m_resp_errorCode( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesDownloadBlock::~CommandCodesDownloadBlock()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesDownloadBlock::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result = CommandCodes::serialize( se );
|
||||
result &= se.write( m_seqNumber, "CommandCodesDownloadBlock: sequence number" );
|
||||
result &= se.write( m_address, "CommandCodesDownloadBlock: address" );
|
||||
result &= se.write( m_numBytes, "CommandCodesDownloadBlock: number of bytes" );
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesDownloadBlock::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result = CommandCodes::deserialize( de );
|
||||
result &= de.read( &m_resp_seqNumber );
|
||||
result &= de.read( &m_resp_errorCode );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesDownloadEnd::CommandCodesDownloadEnd(
|
||||
fb_quadlet_t protocolVersion )
|
||||
: CommandCodes( protocolVersion, eCmdC_DownloadEnd, 2, 0, 2 )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesDownloadEnd::~CommandCodesDownloadEnd()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesDownloadEnd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
return CommandCodes::serialize( se );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesDownloadEnd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result = CommandCodes::deserialize( de );
|
||||
result &= de.read( &m_resp_crc32 );
|
||||
result &= de.read( &m_resp_valid );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesInitializePersParam::CommandCodesInitializePersParam(
|
||||
fb_quadlet_t protocolVersion )
|
||||
: CommandCodes( protocolVersion, eCmdC_InitPersParams, 0, 0, 0 )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesInitializePersParam::~CommandCodesInitializePersParam()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesInitializePersParam::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
return CommandCodes::serialize( se );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesInitializePersParam::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
return CommandCodes::deserialize( de );
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesInitializeConfigToFactorySetting::CommandCodesInitializeConfigToFactorySetting(
|
||||
fb_quadlet_t protocolVersion )
|
||||
: CommandCodes( protocolVersion, eCmdC_InitConfigToFactorySetting, 0, 0, 0 )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesInitializeConfigToFactorySetting::~CommandCodesInitializeConfigToFactorySetting()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesInitializeConfigToFactorySetting::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
return CommandCodes::serialize( se );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesInitializeConfigToFactorySetting::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
return CommandCodes::deserialize( de );
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
BeBoB::CommandCodesGo::CommandCodesGo( fb_quadlet_t protocolVersion,
|
||||
EStartMode startMode )
|
||||
: CommandCodes( protocolVersion, eCmdC_Go, sizeof( m_startMode ), 1, 1 )
|
||||
, m_startMode( startMode )
|
||||
{
|
||||
}
|
||||
|
||||
BeBoB::CommandCodesGo::~CommandCodesGo()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesGo::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result = CommandCodes::serialize( se );
|
||||
result &= se.write( m_startMode, "CommandCodesGo: start mode" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::CommandCodesGo::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result = CommandCodes::deserialize( de );
|
||||
result &= de.read( &m_resp_validCRC );
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef BEBOB_DL_CODES_H
|
||||
#define BEBOB_DL_CODES_H
|
||||
|
||||
#include "fbtypes.h"
|
||||
|
||||
#include "libutil/cmd_serialize.h"
|
||||
|
||||
namespace BeBoB {
|
||||
enum EBootloaderProtocolVersion {
|
||||
eBPV_Unknown = 0,
|
||||
eBPV_V1 = 1,
|
||||
eBPV_V2 = 2,
|
||||
eBPV_V3 = 3,
|
||||
};
|
||||
|
||||
enum EBootloaderCommandCodes {
|
||||
eCmdC_Halt = 0x01,
|
||||
eCmdC_Reset = 0x02,
|
||||
eCmdC_ReadImageCRC = 0x03,
|
||||
eCmdC_DownloadStart = 0x04,
|
||||
eCmdC_DownloadBlock = 0x05,
|
||||
eCmdC_DownloadEnd = 0x06,
|
||||
eCmdC_SwitchTo1394Shell = 0x07,
|
||||
eCmdC_ReadShellChars = 0x08,
|
||||
eCmdC_WriteShellChars = 0x09,
|
||||
eCmdC_ProgramGUID = 0x0a,
|
||||
eCmdC_ProgramMAC = 0x0b,
|
||||
eCmdC_InitPersParams = 0x0c,
|
||||
eCmdC_InitConfigToFactorySetting = 0x0d,
|
||||
eCmdC_SetDebugGUID = 0x0f,
|
||||
eCmdC_ProgramHWIdVersion = 0x10,
|
||||
eCmdC_Go = 0x11,
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodes {
|
||||
public:
|
||||
CommandCodes( fb_quadlet_t protocolVersion,
|
||||
fb_byte_t commandCode,
|
||||
size_t msgSize,
|
||||
fb_byte_t operandSizeRequestField,
|
||||
fb_byte_t operandSizeResponseField );
|
||||
virtual ~CommandCodes();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual size_t getMaxSize();
|
||||
|
||||
EBootloaderCommandCodes getCommandCode() const
|
||||
{ return static_cast<EBootloaderCommandCodes>( m_commandCode ); }
|
||||
|
||||
fb_byte_t getProtocolVersion() const
|
||||
{ return m_protocolVersion; }
|
||||
size_t getMsgSize() const
|
||||
{ return m_msgSize; }
|
||||
fb_byte_t getOperandSizeRequest() const
|
||||
{ return m_operandSizeRequest; }
|
||||
fb_byte_t getOperandSizeResponse() const
|
||||
{ return m_operandSizeResponse; }
|
||||
unsigned short getCommandId() const
|
||||
{ return m_commandId; }
|
||||
|
||||
fb_quadlet_t getRespProtocolVersion() const
|
||||
{ return m_resp_protocolVersion; }
|
||||
unsigned short getRespCommandId() const
|
||||
{ return m_resp_commandId; }
|
||||
fb_byte_t getRespCommandCode() const
|
||||
{ return m_resp_commandCode; }
|
||||
fb_byte_t getRespOperandSize() const
|
||||
{ return m_resp_operandSize; }
|
||||
fb_byte_t getRespSizeInQuadlets() const
|
||||
{ return 2 + m_operandSizeResponse; }
|
||||
|
||||
protected:
|
||||
static unsigned short m_gCommandId;
|
||||
unsigned short m_commandId;
|
||||
fb_quadlet_t m_protocolVersion;
|
||||
fb_byte_t m_commandCode;
|
||||
size_t m_msgSize;
|
||||
fb_byte_t m_operandSizeRequest;
|
||||
fb_byte_t m_operandSizeResponse;
|
||||
|
||||
fb_quadlet_t m_resp_protocolVersion;
|
||||
unsigned short m_resp_commandId;
|
||||
fb_byte_t m_resp_commandCode;
|
||||
fb_byte_t m_resp_operandSize;
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesReset : public CommandCodes {
|
||||
public:
|
||||
enum EStartMode {
|
||||
eSM_Application = 0,
|
||||
eSM_Bootloader,
|
||||
eSM_Debugger,
|
||||
};
|
||||
|
||||
CommandCodesReset( fb_quadlet_t protocolVersion, EStartMode startMode );
|
||||
virtual ~CommandCodesReset();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
EStartMode getStartMode() const
|
||||
{ return static_cast<EStartMode>( m_startMode ); }
|
||||
bool setStartMode( EStartMode startMode )
|
||||
{ m_startMode = startMode; return true; }
|
||||
|
||||
private:
|
||||
fb_byte_t m_startMode;
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesProgramGUID : public CommandCodes {
|
||||
public:
|
||||
CommandCodesProgramGUID( fb_quadlet_t protocolVersion,
|
||||
fb_octlet_t guid );
|
||||
virtual ~CommandCodesProgramGUID();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
fb_octlet_t getGUID() const
|
||||
{ return m_guid; }
|
||||
bool setGUID( fb_octlet_t guid )
|
||||
{ m_guid = guid; return true; }
|
||||
|
||||
private:
|
||||
fb_octlet_t m_guid;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesDownloadStart : public CommandCodes {
|
||||
public:
|
||||
enum EObject {
|
||||
eO_Application = 0,
|
||||
eO_Config = 1,
|
||||
eO_Debugger = 2,
|
||||
eO_Bootloader = 3,
|
||||
eO_WarpImage = 4,
|
||||
eO_SerialBootCode = 5,
|
||||
};
|
||||
|
||||
CommandCodesDownloadStart( fb_quadlet_t protocolVersion,
|
||||
EObject object );
|
||||
virtual ~CommandCodesDownloadStart();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
bool setDate( fb_octlet_t date )
|
||||
{ m_date = date; return true; }
|
||||
bool setTime( fb_octlet_t time )
|
||||
{ m_time = time; return true; }
|
||||
bool setId( fb_quadlet_t id )
|
||||
{ m_id = id; return true; }
|
||||
bool setVersion( fb_quadlet_t version )
|
||||
{ m_version = version; return true; }
|
||||
bool setBaseAddress( fb_quadlet_t address )
|
||||
{ m_address = address; return true; }
|
||||
bool setLength( fb_quadlet_t length )
|
||||
{ m_length = length; return true; }
|
||||
bool setCRC( fb_quadlet_t crc )
|
||||
{ m_crc = crc; return true; }
|
||||
|
||||
int getMaxBlockSize() const
|
||||
{ return m_resp_max_block_size; }
|
||||
|
||||
private:
|
||||
fb_quadlet_t m_object;
|
||||
fb_octlet_t m_date;
|
||||
fb_octlet_t m_time;
|
||||
fb_quadlet_t m_id;
|
||||
fb_quadlet_t m_version;
|
||||
fb_quadlet_t m_address;
|
||||
fb_quadlet_t m_length;
|
||||
fb_quadlet_t m_crc;
|
||||
|
||||
int m_resp_max_block_size;
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesDownloadBlock : public CommandCodes {
|
||||
public:
|
||||
CommandCodesDownloadBlock( fb_quadlet_t protocolVersion );
|
||||
virtual ~CommandCodesDownloadBlock();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
bool setSeqNumber( fb_quadlet_t seqNumber )
|
||||
{ m_seqNumber = seqNumber; return true; }
|
||||
bool setAddress( fb_quadlet_t address )
|
||||
{ m_address = address; return true; }
|
||||
bool setNumberBytes( fb_quadlet_t numByte )
|
||||
{ m_numBytes = numByte; return true; }
|
||||
fb_quadlet_t getRespSeqNumber() const
|
||||
{ return m_resp_seqNumber; }
|
||||
fb_quadlet_t getRespErrorCode() const
|
||||
{ return m_resp_errorCode; }
|
||||
private:
|
||||
fb_quadlet_t m_seqNumber;
|
||||
fb_quadlet_t m_address;
|
||||
fb_quadlet_t m_numBytes;
|
||||
|
||||
fb_quadlet_t m_resp_seqNumber;
|
||||
fb_quadlet_t m_resp_errorCode;
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesDownloadEnd : public CommandCodes {
|
||||
public:
|
||||
CommandCodesDownloadEnd( fb_quadlet_t protocolVersion );
|
||||
virtual ~CommandCodesDownloadEnd();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
fb_quadlet_t getRespCrc32() const
|
||||
{ return m_resp_crc32; }
|
||||
bool getRespIsValid() const
|
||||
{ return m_resp_valid == 0; }
|
||||
|
||||
private:
|
||||
quadlet_t m_resp_crc32;
|
||||
quadlet_t m_resp_valid;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesInitializePersParam : public CommandCodes {
|
||||
public:
|
||||
CommandCodesInitializePersParam( fb_quadlet_t protocolVersion );
|
||||
virtual ~CommandCodesInitializePersParam();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesInitializeConfigToFactorySetting : public CommandCodes {
|
||||
public:
|
||||
CommandCodesInitializeConfigToFactorySetting(
|
||||
fb_quadlet_t protocolVersion );
|
||||
virtual ~CommandCodesInitializeConfigToFactorySetting();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
|
||||
class CommandCodesGo : public CommandCodes {
|
||||
public:
|
||||
enum EStartMode {
|
||||
eSM_Application = 0,
|
||||
eSM_Debugger = 2,
|
||||
};
|
||||
|
||||
CommandCodesGo( fb_quadlet_t protocolVersion, EStartMode startMode );
|
||||
virtual ~CommandCodesGo();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
EStartMode getStartMode() const
|
||||
{ return static_cast<EStartMode>( m_startMode ); }
|
||||
bool setStartMode( EStartMode startMode )
|
||||
{ m_startMode = startMode; return true; }
|
||||
|
||||
fb_quadlet_t getRespIsValidCRC() const
|
||||
{ return m_resp_validCRC; }
|
||||
|
||||
private:
|
||||
fb_quadlet_t m_startMode;
|
||||
fb_quadlet_t m_resp_validCRC;
|
||||
};
|
||||
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,776 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob_dl_mgr.h"
|
||||
#include "bebob_dl_codes.h"
|
||||
#include "bebob_dl_bcd.h"
|
||||
|
||||
#include "libieee1394/configrom.h"
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
#include "libutil/cmd_serialize.h"
|
||||
#include "libutil/Time.h"
|
||||
|
||||
#include "libutil/ByteSwap.h"
|
||||
|
||||
#include "ffadodevice.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <memory>
|
||||
|
||||
namespace BeBoB {
|
||||
enum {
|
||||
AddrRegInfo = 0xffffc8020000ULL,
|
||||
AddrRegReq = 0xffffc8021000ULL,
|
||||
AddrRegReqBuf = 0xffffc8021040ULL,
|
||||
AddrRegResp = 0xffffc8029000ULL,
|
||||
AddrRegRespBuf = 0xffffc8029040ULL,
|
||||
};
|
||||
|
||||
enum {
|
||||
RegInfoManufactorIdOffset = 0x00,
|
||||
RegInfoProtocolVersionOffset = 0x08,
|
||||
RegInfoBootloaderVersionOffset = 0x0c,
|
||||
RegInfoGUID = 0x10,
|
||||
RegInfoHardwareModelId = 0x18,
|
||||
RegInfoHardwareRevision = 0x1c,
|
||||
RegInfoSoftwareDate = 0x20,
|
||||
RegInfoSoftwareTime = 0x28,
|
||||
RegInfoSoftwareId = 0x30,
|
||||
RegInfoSoftwareVersion = 0x34,
|
||||
RegInfoBaseAddress = 0x38,
|
||||
RegInfoMaxImageLen = 0x3c,
|
||||
RegInfoBootloaderDate = 0x40,
|
||||
RegInfoBootloaderTime = 0x48,
|
||||
RegInfoDebuggerDate = 0x50,
|
||||
RegInfoDebuggerTime = 0x58,
|
||||
RegInfoDebuggerId = 0x60,
|
||||
RegInfoDebuggerVersion = 0x64
|
||||
};
|
||||
|
||||
enum {
|
||||
MaxRetries = 10,
|
||||
};
|
||||
|
||||
IMPL_DEBUG_MODULE( BootloaderManager, BootloaderManager, DEBUG_LEVEL_NORMAL );
|
||||
}
|
||||
|
||||
BeBoB::BootloaderManager::BootloaderManager(Ieee1394Service& ieee1349service,
|
||||
fb_nodeid_t nodeId )
|
||||
: m_ieee1394service( &ieee1349service )
|
||||
, m_protocolVersion( eBPV_Unknown )
|
||||
, m_isAppRunning( false )
|
||||
, m_forceEnabled( false )
|
||||
, m_bStartBootloader( true )
|
||||
{
|
||||
memset( &m_cachedInfoRegs, 0, sizeof( m_cachedInfoRegs ) );
|
||||
|
||||
m_configRom = new ConfigRom( *m_ieee1394service, nodeId );
|
||||
// XXX throw exception if initialize fails!
|
||||
m_configRom->initialize();
|
||||
if ( !cacheInfoRegisters() ) {
|
||||
debugError( "BootloaderManager: could not cache info registers\n" );
|
||||
}
|
||||
|
||||
switch( m_cachedInfoRegs.m_protocolVersion ) {
|
||||
case 1:
|
||||
m_protocolVersion = eBPV_V1;
|
||||
break;
|
||||
case 3:
|
||||
m_protocolVersion = eBPV_V3;
|
||||
break;
|
||||
default:
|
||||
// exception?
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_init( &m_mutex, 0 );
|
||||
pthread_cond_init( &m_cond, 0 );
|
||||
|
||||
m_functor = new MemberFunctor0< BeBoB::BootloaderManager*,
|
||||
void (BeBoB::BootloaderManager::*)() >
|
||||
( this, &BeBoB::BootloaderManager::busresetHandler, false );
|
||||
m_ieee1394service->addBusResetHandler( m_functor );
|
||||
}
|
||||
|
||||
BeBoB::BootloaderManager::~BootloaderManager()
|
||||
{
|
||||
m_ieee1394service->remBusResetHandler( m_functor );
|
||||
delete( m_functor );
|
||||
|
||||
delete m_configRom;
|
||||
|
||||
pthread_cond_destroy( &m_cond );
|
||||
pthread_mutex_destroy( &m_mutex );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::cacheInfoRegisters()
|
||||
{
|
||||
if ( !m_configRom->updatedNodeId() ) {
|
||||
debugError( "cacheInfoRegisters: did not find device anymore\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !m_ieee1394service->read(
|
||||
0xffc0 | m_configRom->getNodeId(),
|
||||
AddrRegInfo,
|
||||
sizeof( m_cachedInfoRegs )/4,
|
||||
reinterpret_cast<fb_quadlet_t*>( &m_cachedInfoRegs ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_cachedInfoRegs.m_bootloaderVersion != 0x0 ) {
|
||||
m_isAppRunning = false;
|
||||
} else {
|
||||
m_isAppRunning = true;
|
||||
}
|
||||
|
||||
m_cachedInfoRegs.m_guid = ( m_cachedInfoRegs.m_guid >> 32 )
|
||||
| ( m_cachedInfoRegs.m_guid << 32 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::cacheInfoRegisters( int retries )
|
||||
{
|
||||
for ( int i = 0; i < retries; ++i ) {
|
||||
if ( cacheInfoRegisters() ) {
|
||||
return true;
|
||||
}
|
||||
sleep( 1 );
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
BeBoB::BootloaderManager::getSoftwareDate()
|
||||
{
|
||||
return makeDate( m_cachedInfoRegs.m_softwareDate );
|
||||
}
|
||||
|
||||
std::string
|
||||
BeBoB::BootloaderManager::getSoftwareTime()
|
||||
{
|
||||
return makeDate( m_cachedInfoRegs.m_softwareTime );
|
||||
}
|
||||
|
||||
void
|
||||
BeBoB::BootloaderManager::printInfoRegisters()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
if ( !cacheInfoRegisters() ) {
|
||||
debugError( "Could not read info registers\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
printf( "Info Registers\n" );
|
||||
printf( "\tManufactors Id:\t\t%s\n",
|
||||
makeString( m_cachedInfoRegs.m_manId ).c_str() );
|
||||
printf( "\tProtocol Version:\t0x%08x\n",
|
||||
m_cachedInfoRegs.m_protocolVersion );
|
||||
printf( "\tBootloader Version:\t0x%08x\n",
|
||||
m_cachedInfoRegs.m_bootloaderVersion );
|
||||
printf( "\tGUID:\t\t\t0x%08x%08x\n",
|
||||
( unsigned int )( m_cachedInfoRegs.m_guid >> 32 ),
|
||||
( unsigned int )( m_cachedInfoRegs.m_guid & 0xffffffff ) );
|
||||
printf( "\tHardware Model ID:\t0x%08x\n",
|
||||
m_cachedInfoRegs.m_hardwareModelId );
|
||||
printf( "\tHardware Revision:\t0x%08x\n",
|
||||
m_cachedInfoRegs.m_hardwareRevision );
|
||||
if ( m_cachedInfoRegs.m_softwareDate
|
||||
&& m_cachedInfoRegs.m_softwareTime )
|
||||
{
|
||||
printf( "\tSoftware Date:\t\t%s, %s\n",
|
||||
makeDate( m_cachedInfoRegs.m_softwareDate ).c_str(),
|
||||
makeTime( m_cachedInfoRegs.m_softwareTime ).c_str() );
|
||||
}
|
||||
printf( "\tSoftware Id:\t\t0x%08x\n", m_cachedInfoRegs.m_softwareId );
|
||||
printf( "\tSoftware Version:\t0x%08x\n",
|
||||
m_cachedInfoRegs.m_softwareVersion );
|
||||
printf( "\tBase Address:\t\t0x%08x\n", m_cachedInfoRegs.m_baseAddress );
|
||||
printf( "\tMax. Image Len:\t\t0x%08x\n", m_cachedInfoRegs.m_maxImageLen );
|
||||
if ( m_cachedInfoRegs.m_bootloaderDate
|
||||
&& m_cachedInfoRegs.m_bootloaderTime )
|
||||
{
|
||||
printf( "\tBootloader Date:\t%s, %s\n",
|
||||
makeDate( m_cachedInfoRegs.m_bootloaderDate ).c_str(),
|
||||
makeTime( m_cachedInfoRegs.m_bootloaderTime ).c_str() );
|
||||
}
|
||||
if ( m_cachedInfoRegs.m_debuggerDate
|
||||
&& m_cachedInfoRegs.m_debuggerTime )
|
||||
{
|
||||
printf( "\tDebugger Date:\t\t%s, %s\n",
|
||||
makeDate( m_cachedInfoRegs.m_debuggerDate ).c_str(),
|
||||
makeTime( m_cachedInfoRegs.m_debuggerTime ).c_str() );
|
||||
}
|
||||
printf( "\tDebugger Id:\t\t0x%08x\n", m_cachedInfoRegs.m_debuggerId );
|
||||
printf( "\tDebugger Version:\t0x%08x\n",
|
||||
m_cachedInfoRegs.m_debuggerVersion );
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::downloadFirmware( std::string filename )
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
printf( "parse BCD file\n" );
|
||||
ffado_smartptr<BCD> bcd = ffado_smartptr<BCD>( new BCD( filename ) );
|
||||
if ( !bcd.get() ) {
|
||||
debugError( "downloadFirmware: Could not open or parse BCD '%s'\n",
|
||||
filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
if ( !bcd->parse() ) {
|
||||
debugError( "downloadFirmware: BCD parsing failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "check firmware device compatibility... " );
|
||||
if ( !m_forceEnabled ) {
|
||||
if ( !checkDeviceCompatibility( *bcd ) ) {
|
||||
printf( "failed.\n" );
|
||||
return false;
|
||||
}
|
||||
printf( "ok\n" );
|
||||
} else {
|
||||
printf( "forced\n" );
|
||||
}
|
||||
|
||||
if ( m_bStartBootloader ) {
|
||||
printf( "prepare for download (start bootloader)\n" );
|
||||
if ( !startBootloaderCmd() ) {
|
||||
debugError( "downloadFirmware: Could not start bootloader\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
printf( "start downloading protocol for application image\n" );
|
||||
if ( !downloadObject( *bcd, eOT_Application ) ) {
|
||||
debugError( "downloadFirmware: Firmware download failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "start downloading protocol for CnE\n" );
|
||||
if ( !downloadObject( *bcd, eOT_CnE ) ) {
|
||||
debugError( "downloadFirmware: CnE download failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "setting CnE to factory default settings\n" );
|
||||
if ( !initializeConfigToFactorySettingCmd() ) {
|
||||
debugError( "downloadFirmware: Could not reinitalize CnE\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "start application\n" );
|
||||
if ( !startApplicationCmd() ) {
|
||||
debugError( "downloadFirmware: Could not restart application\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::downloadCnE( std::string filename )
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
printf( "parse BCD file\n" );
|
||||
ffado_smartptr<BCD> bcd = ffado_smartptr<BCD>( new BCD( filename ) );
|
||||
if ( !bcd.get() ) {
|
||||
debugError( "downloadCnE: Could not open or parse BCD '%s'\n",
|
||||
filename.c_str() );
|
||||
return false;
|
||||
}
|
||||
if ( !bcd->parse() ) {
|
||||
debugError( "downloadCnE: BCD parsing failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "check firmware device compatibility... " );
|
||||
if ( !m_forceEnabled ) {
|
||||
if ( !checkDeviceCompatibility( *bcd ) ) {
|
||||
printf( "failed.\n" );
|
||||
return false;
|
||||
}
|
||||
printf( "ok\n" );
|
||||
} else {
|
||||
printf( "forced\n" );
|
||||
}
|
||||
|
||||
if ( m_bStartBootloader ) {
|
||||
printf( "prepare for download (start bootloader)\n" );
|
||||
if ( !startBootloaderCmd() ) {
|
||||
debugError( "downloadCnE: Could not start bootloader\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
printf( "start downloading protocol for CnE\n" );
|
||||
if ( !downloadObject( *bcd, eOT_CnE ) ) {
|
||||
debugError( "downloadCnE: CnE download failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "setting CnE to factory default settings\n" );
|
||||
if ( !initializeConfigToFactorySettingCmd() ) {
|
||||
debugError( "downloadFirmware: Could not reinitalize CnE\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
printf( "start application\n" );
|
||||
if ( !startApplicationCmd() ) {
|
||||
debugError( "downloadCnE: Could not restart application\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::downloadObject( BCD& bcd, EObjectType eObject )
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
CommandCodesDownloadStart::EObject eCCDSObject;
|
||||
fb_quadlet_t baseAddress;
|
||||
fb_quadlet_t imageLength;
|
||||
fb_quadlet_t crc;
|
||||
fb_quadlet_t offset;
|
||||
|
||||
switch ( eObject ) {
|
||||
case eOT_Application:
|
||||
eCCDSObject = CommandCodesDownloadStart::eO_Application;
|
||||
baseAddress = bcd.getImageBaseAddress();
|
||||
imageLength = bcd.getImageLength();
|
||||
crc = bcd.getImageCRC();
|
||||
offset = bcd.getImageOffset();
|
||||
break;
|
||||
case eOT_CnE:
|
||||
eCCDSObject = CommandCodesDownloadStart::eO_Config;
|
||||
baseAddress = 0;
|
||||
imageLength = bcd.getCnELength();
|
||||
crc = bcd.getCnECRC();
|
||||
offset = bcd.getCnEOffset();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandCodesDownloadStart ccDStart ( m_protocolVersion, eCCDSObject );
|
||||
ccDStart.setDate( bcd.getSoftwareDate() );
|
||||
ccDStart.setTime( bcd.getSoftwareTime() );
|
||||
ccDStart.setId( bcd.getSoftwareId() );
|
||||
ccDStart.setVersion( bcd.getSoftwareVersion() );
|
||||
ccDStart.setBaseAddress( baseAddress );
|
||||
ccDStart.setLength( imageLength );
|
||||
ccDStart.setCRC( crc );
|
||||
|
||||
if ( !writeRequest( ccDStart ) ) {
|
||||
debugError( "downloadObject: start command write request failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// bootloader erases the flash, have to wait until is ready
|
||||
// to answer our next request
|
||||
printf( "wait until flash erasing has terminated\n" );
|
||||
int cnt = 30;
|
||||
while(cnt--) {
|
||||
sleep( 1 );
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if ( !readResponse( ccDStart ) ) {
|
||||
debugError( "downloadObject: (start) command read request failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ccDStart.getMaxBlockSize() < 0 ) {
|
||||
debugError( "downloadObject: (start) command reported error %d\n",
|
||||
ccDStart.getMaxBlockSize() );
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int maxBlockSize = m_configRom->getAsyMaxPayload();
|
||||
unsigned int i = 0;
|
||||
fb_quadlet_t address = 0;
|
||||
bool result = true;
|
||||
int totalBytes = imageLength;
|
||||
int downloadedBytes = 0;
|
||||
while ( imageLength > 0 ) {
|
||||
unsigned int blockSize = imageLength > maxBlockSize ?
|
||||
maxBlockSize : imageLength;
|
||||
|
||||
fb_byte_t block[blockSize];
|
||||
if ( !bcd.read( offset, block, blockSize ) ) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !get1394Serivce()->write(
|
||||
0xffc0 | getConfigRom()->getNodeId(),
|
||||
AddrRegReqBuf,
|
||||
( blockSize + 3 ) / 4,
|
||||
reinterpret_cast<fb_quadlet_t*>( block ) ) )
|
||||
{
|
||||
debugError( "downloadObject: Could not write to node %d\n",
|
||||
getConfigRom()->getNodeId() );
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandCodesDownloadBlock ccBlock( m_protocolVersion );
|
||||
ccBlock.setSeqNumber( i );
|
||||
ccBlock.setAddress( baseAddress + address );
|
||||
ccBlock.setNumberBytes( blockSize );
|
||||
|
||||
if ( !writeRequest( ccBlock ) ) {
|
||||
debugError( "downloadObject: (block) write request failed\n" );
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
SleepRelativeUsec( 100 );
|
||||
|
||||
if ( !readResponse( ccBlock ) ) {
|
||||
debugError( "downloadObject: (block) read request failed\n" );
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( i != ccBlock.getRespSeqNumber() ) {
|
||||
debugError( "downloadObject: (block) wrong sequence number "
|
||||
"reported. %d expected, %d reported\n",
|
||||
i, ccBlock.getRespSeqNumber() );
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
if ( ccBlock.getRespErrorCode() != 0 ) {
|
||||
debugError( "downloadObject: (block) failed download with "
|
||||
"error code 0x%08x\n", ccBlock.getRespErrorCode() );
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
downloadedBytes += blockSize;
|
||||
if ( ( i % 100 ) == 0 ) {
|
||||
printf( "%10d/%d bytes downloaded\r",
|
||||
downloadedBytes, totalBytes );
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
imageLength -= blockSize;
|
||||
address += blockSize;
|
||||
offset += blockSize;
|
||||
i++;
|
||||
}
|
||||
printf( "%10d/%d bytes downloaded\n",
|
||||
downloadedBytes, totalBytes );
|
||||
|
||||
if ( !result ) {
|
||||
debugError( "downloadObject: seqNumber = %d, "
|
||||
"address = 0%08x, offset = 0x%08x, "
|
||||
"restImageLength = 0x%08x\n",
|
||||
i, address, offset, imageLength );
|
||||
}
|
||||
|
||||
CommandCodesDownloadEnd ccEnd( m_protocolVersion );
|
||||
if ( !writeRequest( ccEnd ) ) {
|
||||
debugError( "downloadObject: (end) command write failed\n" );
|
||||
}
|
||||
|
||||
printf( "wait for transaction completion\n" );
|
||||
cnt = 10;
|
||||
while(cnt--) {
|
||||
sleep( 1 );
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if ( !readResponse( ccEnd ) ) {
|
||||
debugError( "downloadObject: (end) command read failed\n" );
|
||||
}
|
||||
|
||||
if ( result ) {
|
||||
if ( ccEnd.getRespIsValid() ) {
|
||||
if ( ccEnd.getRespCrc32() == crc ) {
|
||||
debugOutput( DebugModule::eDL_Normal,
|
||||
"downloadObject: CRC match\n" );
|
||||
} else {
|
||||
debugError( "downloadObject: CRC mismatch. 0x%08x expected, "
|
||||
"0x%08x reported",
|
||||
crc, ccEnd.getRespCrc32() );
|
||||
result = false;
|
||||
}
|
||||
} else {
|
||||
debugError( "downloadObject: (end) object is not valid\n" );
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
printf( "download protocol successfully completed\n" );
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::programGUID( fb_octlet_t guid )
|
||||
{
|
||||
if ( m_bStartBootloader ) {
|
||||
if ( !startBootloaderCmd() ) {
|
||||
debugError( "programGUID: Could not start bootloader\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !programGUIDCmd( guid ) ) {
|
||||
debugError( "programGUID: Could not program guid\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !startApplicationCmd() ) {
|
||||
debugError( "Could not restart application\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BeBoB::BootloaderManager::busresetHandler()
|
||||
{
|
||||
pthread_cond_signal( &m_cond );
|
||||
}
|
||||
|
||||
void
|
||||
BeBoB::BootloaderManager::waitForBusReset()
|
||||
{
|
||||
struct timespec timeout;
|
||||
int retcode;
|
||||
// pthread_cond_timedwait() uses CLOCK_REALTIME to evaluate its
|
||||
// timeout argument.
|
||||
clock_gettime(CLOCK_REALTIME, &timeout);
|
||||
do {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
timeout.tv_sec = timeout.tv_sec + 1;
|
||||
retcode = pthread_cond_timedwait( &m_cond, &m_mutex, &timeout );
|
||||
} while (retcode == ETIMEDOUT);
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::writeRequest( CommandCodes& cmd )
|
||||
{
|
||||
unsigned char buf[ ( ( cmd.getMaxSize()+3 )/4 ) * 4 ];
|
||||
memset( buf, 0, sizeof( buf ) );
|
||||
|
||||
Util::Cmd::BufferSerialize se( buf, sizeof( buf ) );
|
||||
if ( !cmd.serialize( se ) ) {
|
||||
debugError( "writeRequest: Could not serialize command code %d\n",
|
||||
cmd.getCommandCode() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !get1394Serivce()->write(
|
||||
0xffc0 | getConfigRom()->getNodeId(),
|
||||
AddrRegReq,
|
||||
sizeof( buf )/4,
|
||||
reinterpret_cast<fb_quadlet_t*>( buf ) ) )
|
||||
{
|
||||
debugError( "writeRequest: Could not ARM write to node %d\n",
|
||||
getConfigRom()->getNodeId() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::readResponse( CommandCodes& writeRequestCmd )
|
||||
{
|
||||
const size_t buf_length = 0x40;
|
||||
unsigned char raw[buf_length];
|
||||
if ( !get1394Serivce()->read(
|
||||
0xffc0 | getConfigRom()->getNodeId(),
|
||||
AddrRegResp,
|
||||
writeRequestCmd.getRespSizeInQuadlets(),
|
||||
reinterpret_cast<fb_quadlet_t*>( raw ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Util::Cmd::BufferDeserialize de( raw, buf_length );
|
||||
if ( !writeRequestCmd.deserialize( de ) ) {
|
||||
debugError( "readResponse: deserialize failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result =
|
||||
writeRequestCmd.getProtocolVersion()
|
||||
== writeRequestCmd.getRespProtocolVersion();
|
||||
result &=
|
||||
writeRequestCmd.getCommandId()
|
||||
== writeRequestCmd.getRespCommandId();
|
||||
result &=
|
||||
writeRequestCmd.getCommandCode()
|
||||
== writeRequestCmd.getRespCommandCode();
|
||||
#ifdef DEBUG
|
||||
if ( !result ) {
|
||||
debugError( "readResponse: protocol version: %d expected, "
|
||||
" %d reported\n",
|
||||
writeRequestCmd.getProtocolVersion(),
|
||||
writeRequestCmd.getRespProtocolVersion() );
|
||||
debugError( "readResponse: command id: %d expected, "
|
||||
" %d reported\n",
|
||||
writeRequestCmd.getCommandId(),
|
||||
writeRequestCmd.getRespCommandId() );
|
||||
debugError( "readResponse: command code: %d expected, "
|
||||
" %d reported\n",
|
||||
writeRequestCmd.getCommandCode(),
|
||||
writeRequestCmd.getRespCommandCode() );
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::startBootloaderCmd()
|
||||
{
|
||||
CommandCodesReset cmd( m_protocolVersion,
|
||||
CommandCodesReset::eSM_Bootloader ) ;
|
||||
if ( !writeRequest( cmd ) ) {
|
||||
debugError( "startBootloaderCmd: writeRequest failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
waitForBusReset();
|
||||
if ( !cacheInfoRegisters( MaxRetries ) ) {
|
||||
debugError( "startBootloaderCmd: Could not read info registers\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// wait for bootloader finish startup sequence
|
||||
// there is no way to find out when it has finished
|
||||
sleep( 10 );
|
||||
int cnt = 10;
|
||||
while(cnt--) {
|
||||
sleep( 1 );
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::startApplicationCmd()
|
||||
{
|
||||
CommandCodesGo cmd( m_protocolVersion,
|
||||
CommandCodesGo::eSM_Application ) ;
|
||||
if ( !writeRequest( cmd ) ) {
|
||||
debugError( "startApplicationCmd: writeRequest failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::programGUIDCmd( fb_octlet_t guid )
|
||||
{
|
||||
CommandCodesProgramGUID cmd( m_protocolVersion, guid );
|
||||
if ( !writeRequest( cmd ) ) {
|
||||
debugError( "programGUIDCmd: writeRequest failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep( 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::initializePersParamCmd()
|
||||
{
|
||||
CommandCodesInitializePersParam cmd( m_protocolVersion );
|
||||
if ( !writeRequest( cmd ) ) {
|
||||
debugError( "initializePersParamCmd: writeRequest failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep( 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::initializeConfigToFactorySettingCmd()
|
||||
{
|
||||
CommandCodesInitializeConfigToFactorySetting cmd( m_protocolVersion );
|
||||
if ( !writeRequest( cmd ) ) {
|
||||
debugError( "initializeConfigToFactorySettingCmd: writeRequest failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep( 5 );
|
||||
int cnt = 5;
|
||||
while(cnt--) {
|
||||
sleep( 1 );
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BeBoB::BootloaderManager::checkDeviceCompatibility( BCD& bcd )
|
||||
{
|
||||
fb_quadlet_t vendorOUI = ( m_cachedInfoRegs.m_guid >> 40 );
|
||||
|
||||
|
||||
if ( ( vendorOUI == bcd.getVendorOUI() )
|
||||
&& ( m_cachedInfoRegs.m_softwareId == bcd.getSoftwareId() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
printf( "vendorOUI = 0x%08x\n", vendorOUI );
|
||||
printf( "BCD vendorOUI = 0x%08x\n", bcd.getVendorOUI() );
|
||||
printf( "software ID = 0x%08x\n", m_cachedInfoRegs.m_softwareId );
|
||||
printf( "BCD software ID = 0x%08x\n", bcd.getSoftwareId() );
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_DL_MGR_H
|
||||
#define BEBOB_DL_MGR_H
|
||||
|
||||
#include "bebob_dl_codes.h"
|
||||
|
||||
#include "fbtypes.h"
|
||||
#include "libutil/Functors.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class Ieee1394Service;
|
||||
class ConfigRom;
|
||||
|
||||
using namespace Util;
|
||||
|
||||
namespace BeBoB {
|
||||
class BCD;
|
||||
|
||||
class BootloaderManager {
|
||||
public:
|
||||
BootloaderManager( Ieee1394Service& ieee1349service,
|
||||
fb_nodeid_t nodeId );
|
||||
~BootloaderManager();
|
||||
|
||||
const ConfigRom* const getConfigRom() const
|
||||
{ return m_configRom; }
|
||||
|
||||
void printInfoRegisters();
|
||||
|
||||
bool downloadFirmware( std::string filename );
|
||||
bool downloadCnE( std::string filename );
|
||||
bool programGUID( octlet_t guid );
|
||||
|
||||
void busresetHandler();
|
||||
|
||||
Ieee1394Service* get1394Serivce() const
|
||||
{ return m_ieee1394service; }
|
||||
|
||||
bool setForceOperations( bool enabled )
|
||||
{ m_forceEnabled = enabled; return true; }
|
||||
|
||||
bool setStartBootloader( bool bStartBootloader )
|
||||
{ m_bStartBootloader = bStartBootloader; return true; }
|
||||
|
||||
int getSoftwareVersion() {return m_cachedInfoRegs.m_softwareVersion;};
|
||||
std::string getSoftwareDate();
|
||||
std::string getSoftwareTime();
|
||||
|
||||
protected:
|
||||
enum EObjectType {
|
||||
eOT_Application,
|
||||
eOT_CnE
|
||||
};
|
||||
|
||||
void waitForBusReset();
|
||||
bool writeRequest( CommandCodes& cmd );
|
||||
bool readResponse( CommandCodes& writeRequestCmd );
|
||||
bool downloadObject( BCD& bcd, EObjectType eObject );
|
||||
|
||||
bool programGUIDCmd( octlet_t guid );
|
||||
bool startBootloaderCmd();
|
||||
bool startApplicationCmd();
|
||||
bool initializePersParamCmd();
|
||||
bool initializeConfigToFactorySettingCmd();
|
||||
bool checkDeviceCompatibility( BCD& bcd );
|
||||
|
||||
private:
|
||||
bool cacheInfoRegisters();
|
||||
bool cacheInfoRegisters( int retries );
|
||||
|
||||
struct info_register_t {
|
||||
fb_octlet_t m_manId;
|
||||
fb_quadlet_t m_protocolVersion;
|
||||
fb_quadlet_t m_bootloaderVersion;
|
||||
fb_octlet_t m_guid;
|
||||
fb_quadlet_t m_hardwareModelId;
|
||||
fb_quadlet_t m_hardwareRevision;
|
||||
fb_octlet_t m_softwareDate;
|
||||
fb_octlet_t m_softwareTime;
|
||||
fb_quadlet_t m_softwareId;
|
||||
fb_quadlet_t m_softwareVersion;
|
||||
fb_quadlet_t m_baseAddress;
|
||||
fb_quadlet_t m_maxImageLen;
|
||||
fb_octlet_t m_bootloaderDate;
|
||||
fb_octlet_t m_bootloaderTime;
|
||||
fb_octlet_t m_debuggerDate;
|
||||
fb_octlet_t m_debuggerTime;
|
||||
fb_quadlet_t m_debuggerId;
|
||||
fb_quadlet_t m_debuggerVersion;
|
||||
};
|
||||
|
||||
Ieee1394Service* m_ieee1394service;
|
||||
ConfigRom* m_configRom;
|
||||
|
||||
EBootloaderProtocolVersion m_protocolVersion;
|
||||
bool m_isAppRunning;
|
||||
info_register_t m_cachedInfoRegs;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
Functor* m_functor;
|
||||
|
||||
bool m_forceEnabled;
|
||||
bool m_bStartBootloader;
|
||||
|
||||
DECLARE_DEBUG_MODULE;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,581 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob/bebob_functionblock.h"
|
||||
#include "bebob/bebob_avdevice_subunit.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
#include "libieee1394/configrom.h"
|
||||
|
||||
#include "libutil/cmd_serialize.h"
|
||||
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
IMPL_DEBUG_MODULE( FunctionBlock, FunctionBlock, DEBUG_LEVEL_NORMAL );
|
||||
|
||||
FunctionBlock::FunctionBlock(
|
||||
AVC::Subunit& subunit,
|
||||
function_block_type_t type,
|
||||
function_block_type_t subtype,
|
||||
function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
no_of_input_plugs_t nrOfInputPlugs,
|
||||
no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose )
|
||||
: m_subunit( &subunit )
|
||||
, m_type( type )
|
||||
, m_subtype( subtype )
|
||||
, m_id( id )
|
||||
, m_purpose( purpose )
|
||||
, m_nrOfInputPlugs( nrOfInputPlugs )
|
||||
, m_nrOfOutputPlugs( nrOfOutputPlugs )
|
||||
, m_verbose( verbose )
|
||||
{
|
||||
setDebugLevel( verbose );
|
||||
}
|
||||
|
||||
FunctionBlock::FunctionBlock( const FunctionBlock& rhs )
|
||||
: m_subunit( rhs.m_subunit )
|
||||
, m_type( rhs.m_type )
|
||||
, m_subtype( rhs.m_subtype )
|
||||
, m_id( rhs.m_id )
|
||||
, m_purpose( rhs.m_purpose )
|
||||
, m_nrOfInputPlugs( rhs.m_nrOfInputPlugs )
|
||||
, m_nrOfOutputPlugs( rhs.m_nrOfOutputPlugs )
|
||||
, m_verbose( rhs.m_verbose )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlock::FunctionBlock()
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlock::~FunctionBlock()
|
||||
{
|
||||
for ( PlugVector::iterator it = m_plugs.begin();
|
||||
it != m_plugs.end();
|
||||
++it )
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlock::discover()
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_NORMAL,
|
||||
"discover function block %s (nr of input plugs = %d, "
|
||||
"nr of output plugs = %d)\n",
|
||||
getName(),
|
||||
m_nrOfInputPlugs,
|
||||
m_nrOfOutputPlugs );
|
||||
|
||||
if ( !discoverPlugs( AVC::Plug::eAPD_Input, m_nrOfInputPlugs ) ) {
|
||||
debugError( "Could not discover input plug for '%s'\n",
|
||||
getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !discoverPlugs( AVC::Plug::eAPD_Output, m_nrOfOutputPlugs ) ) {
|
||||
debugError( "Could not discover output plugs for '%s'\n",
|
||||
getName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlock::discoverPlugs( AVC::Plug::EPlugDirection plugDirection,
|
||||
plug_id_t plugMaxId )
|
||||
{
|
||||
for ( int plugId = 0; plugId < plugMaxId; ++plugId ) {
|
||||
AVC::Plug* plug = new BeBoB::Plug(
|
||||
&m_subunit->getUnit(),
|
||||
m_subunit,
|
||||
m_type,
|
||||
m_id,
|
||||
AVC::Plug::eAPA_FunctionBlockPlug,
|
||||
plugDirection,
|
||||
plugId);
|
||||
|
||||
if ( !plug || !plug->discover() ) {
|
||||
debugError( "plug discovering failed for plug %d\n",
|
||||
plugId );
|
||||
delete plug;
|
||||
return false;
|
||||
}
|
||||
|
||||
debugOutput( DEBUG_LEVEL_NORMAL, "plug '%s' found\n",
|
||||
plug->getName() );
|
||||
m_plugs.push_back( plug );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlock::discoverConnections()
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE,
|
||||
"discover connections function block %s\n",
|
||||
getName() );
|
||||
|
||||
for ( PlugVector::iterator it = m_plugs.begin();
|
||||
it != m_plugs.end();
|
||||
++it )
|
||||
{
|
||||
BeBoB::Plug* plug = dynamic_cast<BeBoB::Plug*>(*it);
|
||||
if(!plug) {
|
||||
debugError("BUG: not a bebob plug\n");
|
||||
return false;
|
||||
}
|
||||
if ( !plug->discoverConnections() ) {
|
||||
debugError( "Could not discover plug connections\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlock::serialize( std::string basePath, Util::IOSerialize& ser ) const
|
||||
{
|
||||
bool result;
|
||||
|
||||
result = ser.write( basePath + "m_type", m_type );
|
||||
result &= ser.write( basePath + "m_subtype", m_subtype );
|
||||
result &= ser.write( basePath + "m_id", m_id );
|
||||
result &= ser.write( basePath + "m_purpose", m_purpose );
|
||||
result &= ser.write( basePath + "m_nrOfInputPlugs", m_nrOfInputPlugs );
|
||||
result &= ser.write( basePath + "m_nrOfOutputPlugs", m_nrOfOutputPlugs );
|
||||
result &= serializePlugVector( basePath + "m_plugs", ser, m_plugs );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FunctionBlock*
|
||||
FunctionBlock::deserialize( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AVC::Unit& unit,
|
||||
AVC::Subunit& subunit )
|
||||
{
|
||||
bool result;
|
||||
function_block_type_t type;
|
||||
function_block_type_t subtype;
|
||||
FunctionBlock* pFB = 0;
|
||||
|
||||
if ( !deser.isExisting( basePath + "m_type" ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = deser.read( basePath + "m_type", type );
|
||||
result &= deser.read( basePath + "m_subtype", subtype );
|
||||
if ( !result ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch ( type ) {
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitSelector:
|
||||
pFB = new FunctionBlockSelector;
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitFeature:
|
||||
pFB = new FunctionBlockFeature;
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitProcessing:
|
||||
if ( subtype == ExtendedSubunitInfoCmd::ePT_EnhancedMixer ) {
|
||||
pFB = new FunctionBlockEnhancedMixer;
|
||||
} else {
|
||||
pFB = new FunctionBlockProcessing;
|
||||
}
|
||||
break;
|
||||
case ExtendedSubunitInfoCmd::eFBT_AudioSubunitCodec:
|
||||
pFB = new FunctionBlockCodec;
|
||||
break;
|
||||
default:
|
||||
pFB = 0;
|
||||
}
|
||||
|
||||
if ( !pFB ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pFB->m_subunit = &subunit;
|
||||
pFB->m_type = type;
|
||||
pFB->m_subtype = subtype;
|
||||
|
||||
result &= deser.read( basePath + "m_id", pFB->m_id );
|
||||
result &= deser.read( basePath + "m_purpose", pFB->m_purpose );
|
||||
result &= deser.read( basePath + "m_nrOfInputPlugs", pFB->m_nrOfInputPlugs );
|
||||
result &= deser.read( basePath + "m_nrOfOutputPlugs", pFB->m_nrOfOutputPlugs );
|
||||
|
||||
if ( !result ) {
|
||||
delete pFB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pFB;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlock::deserializeUpdate( std::string basePath,
|
||||
Util::IODeserialize& deser )
|
||||
{
|
||||
bool result;
|
||||
|
||||
result = deserializePlugVector( basePath + "m_plugs", deser,
|
||||
m_subunit->getUnit().getPlugManager(), m_plugs );
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
FunctionBlockSelector::FunctionBlockSelector(
|
||||
AVC::Subunit& subunit,
|
||||
function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
no_of_input_plugs_t nrOfInputPlugs,
|
||||
no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose )
|
||||
: FunctionBlock( subunit,
|
||||
eFBT_AudioSubunitSelector,
|
||||
0,
|
||||
id,
|
||||
purpose,
|
||||
nrOfInputPlugs,
|
||||
nrOfOutputPlugs,
|
||||
verbose )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockSelector::FunctionBlockSelector(
|
||||
const FunctionBlockSelector& rhs )
|
||||
: FunctionBlock( rhs )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockSelector::FunctionBlockSelector()
|
||||
: FunctionBlock()
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockSelector::~FunctionBlockSelector()
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
FunctionBlockSelector::getName()
|
||||
{
|
||||
return "Selector";
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockSelector::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockSelector::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& unit )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
FunctionBlockFeature::FunctionBlockFeature(
|
||||
AVC::Subunit& subunit,
|
||||
function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
no_of_input_plugs_t nrOfInputPlugs,
|
||||
no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose )
|
||||
: FunctionBlock( subunit,
|
||||
eFBT_AudioSubunitFeature,
|
||||
0,
|
||||
id,
|
||||
purpose,
|
||||
nrOfInputPlugs,
|
||||
nrOfOutputPlugs,
|
||||
verbose )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockFeature::FunctionBlockFeature(
|
||||
const FunctionBlockFeature& rhs )
|
||||
: FunctionBlock( rhs )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockFeature::FunctionBlockFeature()
|
||||
: FunctionBlock()
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockFeature::~FunctionBlockFeature()
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
FunctionBlockFeature::getName()
|
||||
{
|
||||
return "Feature";
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockFeature::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockFeature::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& unit )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
FunctionBlockEnhancedMixer::FunctionBlockEnhancedMixer(
|
||||
AVC::Subunit& subunit,
|
||||
function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
no_of_input_plugs_t nrOfInputPlugs,
|
||||
no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose )
|
||||
: FunctionBlock( subunit,
|
||||
eFBT_AudioSubunitProcessing,
|
||||
ExtendedSubunitInfoCmd::ePT_EnhancedMixer,
|
||||
id,
|
||||
purpose,
|
||||
nrOfInputPlugs,
|
||||
nrOfOutputPlugs,
|
||||
verbose )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockEnhancedMixer::FunctionBlockEnhancedMixer(
|
||||
const FunctionBlockEnhancedMixer& rhs )
|
||||
: FunctionBlock( rhs )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockEnhancedMixer::FunctionBlockEnhancedMixer()
|
||||
: FunctionBlock()
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockEnhancedMixer::~FunctionBlockEnhancedMixer()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockEnhancedMixer::discover()
|
||||
{
|
||||
if (!FunctionBlock::discover())
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Disable discovering of enhanced mixer because all
|
||||
* device out there do not use, and all implementations
|
||||
* are buggy. So there is no point to use it.
|
||||
* All 'mixer' functions are implemented with selector function blocks
|
||||
*/
|
||||
AVC::FunctionBlockCmd fbCmd( m_subunit->getUnit().get1394Service(),
|
||||
FunctionBlockCmd::eFBT_Processing,
|
||||
m_id,
|
||||
FunctionBlockCmd::eCA_Current);
|
||||
fbCmd.setNodeId( m_subunit->getUnit().getConfigRom().getNodeId() );
|
||||
fbCmd.setSubunitId( 0x00 );
|
||||
fbCmd.setCommandType( AVCCommand::eCT_Status );
|
||||
// fbCmd.setVerboseLevel( DEBUG_LEVEL_VERY_VERBOSE );
|
||||
|
||||
// Ok, this enhanced mixer setting here is just a hack, we need
|
||||
// a sane way to set processing features (read pointer management)
|
||||
AVC::FunctionBlockProcessingEnhancedMixer em;
|
||||
delete fbCmd.m_pFBProcessing->m_pMixer;
|
||||
fbCmd.m_pFBProcessing->m_pMixer = 0;
|
||||
fbCmd.m_pFBProcessing->m_pEnhancedMixer = em.clone();
|
||||
|
||||
fbCmd.m_pFBProcessing->m_inputAudioChannelNumber = 0xff;
|
||||
fbCmd.m_pFBProcessing->m_outputAudioChannelNumber = 0xff;
|
||||
|
||||
if ( !fbCmd.fire() ) {
|
||||
debugError( "cmd failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// if ( getDebugLevel() >= DEBUG_LEVEL_NORMAL ) {
|
||||
// Util::Cmd::CoutSerializer se;
|
||||
// fbCmd.serialize( se );
|
||||
// }
|
||||
|
||||
if((fbCmd.getResponse() != AVCCommand::eR_Implemented)) {
|
||||
debugWarning("fbCmd.getResponse() != AVCCommand::eR_Implemented\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
FunctionBlockEnhancedMixer::getName()
|
||||
{
|
||||
return "EnhancedMixer";
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockEnhancedMixer::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockEnhancedMixer::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& unit )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
FunctionBlockProcessing::FunctionBlockProcessing(
|
||||
AVC::Subunit& subunit,
|
||||
function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
no_of_input_plugs_t nrOfInputPlugs,
|
||||
no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose )
|
||||
: FunctionBlock( subunit,
|
||||
eFBT_AudioSubunitProcessing,
|
||||
0,
|
||||
id,
|
||||
purpose,
|
||||
nrOfInputPlugs,
|
||||
nrOfOutputPlugs,
|
||||
verbose )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockProcessing::FunctionBlockProcessing(
|
||||
const FunctionBlockProcessing& rhs )
|
||||
: FunctionBlock( rhs )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockProcessing::FunctionBlockProcessing()
|
||||
: FunctionBlock()
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockProcessing::~FunctionBlockProcessing()
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
FunctionBlockProcessing::getName()
|
||||
{
|
||||
return "Dummy Processing";
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockProcessing::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockProcessing::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& unit )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
FunctionBlockCodec::FunctionBlockCodec(
|
||||
AVC::Subunit& subunit,
|
||||
function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
no_of_input_plugs_t nrOfInputPlugs,
|
||||
no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose )
|
||||
: FunctionBlock( subunit,
|
||||
eFBT_AudioSubunitCodec,
|
||||
0,
|
||||
id,
|
||||
purpose,
|
||||
nrOfInputPlugs,
|
||||
nrOfOutputPlugs,
|
||||
verbose )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockCodec::FunctionBlockCodec( const FunctionBlockCodec& rhs )
|
||||
: FunctionBlock( rhs )
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockCodec::FunctionBlockCodec()
|
||||
: FunctionBlock()
|
||||
{
|
||||
}
|
||||
|
||||
FunctionBlockCodec::~FunctionBlockCodec()
|
||||
{
|
||||
}
|
||||
|
||||
const char*
|
||||
FunctionBlockCodec::getName()
|
||||
{
|
||||
return "Dummy Codec";
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockCodec::serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FunctionBlockCodec::deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& unit )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_FUNCTION_BLOCK_H
|
||||
#define BEBOB_FUNCTION_BLOCK_H
|
||||
|
||||
#include "bebob/bebob_avplug.h"
|
||||
|
||||
#include "libavc/avc_definitions.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace AVC {
|
||||
class Subunit;
|
||||
}
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
class FunctionBlock {
|
||||
public:
|
||||
enum EFunctionBlockType {
|
||||
eFBT_AllFunctionBlockType = 0xff,
|
||||
eFBT_AudioSubunitSelector = 0x80,
|
||||
eFBT_AudioSubunitFeature = 0x81,
|
||||
eFBT_AudioSubunitProcessing = 0x82,
|
||||
eFBT_AudioSubunitCodec = 0x83,
|
||||
};
|
||||
|
||||
enum ESpecialPurpose {
|
||||
eSP_InputGain,
|
||||
eSP_OutputVolume,
|
||||
eSP_NoSpecialPurpose
|
||||
};
|
||||
|
||||
FunctionBlock( AVC::Subunit& subunit,
|
||||
AVC::function_block_type_t type,
|
||||
AVC::function_block_type_t subtype,
|
||||
AVC::function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
AVC::no_of_input_plugs_t nrOfInputPlugs,
|
||||
AVC::no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose );
|
||||
FunctionBlock( const FunctionBlock& rhs );
|
||||
FunctionBlock();
|
||||
virtual ~FunctionBlock();
|
||||
|
||||
virtual bool discover();
|
||||
virtual bool discoverConnections();
|
||||
|
||||
virtual const char* getName() = 0;
|
||||
|
||||
AVC::function_block_type_t getType() {return m_type;};
|
||||
AVC::function_block_type_t getSubtype() {return m_subtype;};
|
||||
AVC::function_block_id_t getId() {return m_id;};
|
||||
|
||||
AVC::no_of_input_plugs_t getNrOfInputPlugs() {return m_nrOfInputPlugs;};
|
||||
AVC::no_of_output_plugs_t getNrOfOutputPlugs() {return m_nrOfOutputPlugs;};
|
||||
|
||||
bool serialize( std::string basePath, Util::IOSerialize& ser ) const;
|
||||
|
||||
static FunctionBlock* deserialize( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AVC::Unit& unit,
|
||||
AVC::Subunit& subunit );
|
||||
bool deserializeUpdate( std::string basePath,
|
||||
Util::IODeserialize& deser );
|
||||
protected:
|
||||
bool discoverPlugs( AVC::Plug::EPlugDirection plugDirection,
|
||||
AVC::plug_id_t plugMaxId );
|
||||
|
||||
protected:
|
||||
AVC::Subunit* m_subunit;
|
||||
AVC::function_block_type_t m_type;
|
||||
AVC::function_block_type_t m_subtype;
|
||||
AVC::function_block_id_t m_id;
|
||||
ESpecialPurpose m_purpose;
|
||||
AVC::no_of_input_plugs_t m_nrOfInputPlugs;
|
||||
AVC::no_of_output_plugs_t m_nrOfOutputPlugs;
|
||||
int m_verbose;
|
||||
AVC::PlugVector m_plugs;
|
||||
|
||||
DECLARE_DEBUG_MODULE;
|
||||
};
|
||||
|
||||
typedef std::vector<FunctionBlock*> FunctionBlockVector;
|
||||
|
||||
/////////////////////////////////////
|
||||
/////////////////////////////////////
|
||||
|
||||
class FunctionBlockSelector: public FunctionBlock
|
||||
{
|
||||
public:
|
||||
FunctionBlockSelector(AVC::Subunit& subunit,
|
||||
AVC::function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
AVC::no_of_input_plugs_t nrOfInputPlugs,
|
||||
AVC::no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose);
|
||||
FunctionBlockSelector( const FunctionBlockSelector& rhs );
|
||||
FunctionBlockSelector();
|
||||
virtual ~FunctionBlockSelector();
|
||||
|
||||
virtual const char* getName();
|
||||
|
||||
protected:
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& avDevice );
|
||||
};
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
class FunctionBlockFeature: public FunctionBlock
|
||||
{
|
||||
public:
|
||||
FunctionBlockFeature(AVC::Subunit& subunit,
|
||||
AVC::function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
AVC::no_of_input_plugs_t nrOfInputPlugs,
|
||||
AVC::no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose);
|
||||
FunctionBlockFeature( const FunctionBlockFeature& rhs );
|
||||
FunctionBlockFeature();
|
||||
virtual ~FunctionBlockFeature();
|
||||
|
||||
virtual const char* getName();
|
||||
|
||||
// FIXME: this is not pretty!
|
||||
enum EControlSelectorEncoding {
|
||||
eCSE_Feature_Unknown = 0x00,
|
||||
eCSE_Feature_Mute = 0x01,
|
||||
eCSE_Feature_Volume = 0x02,
|
||||
eCSE_Feature_LRBalance = 0x03,
|
||||
eCSE_Feature_FRBalance = 0x04,
|
||||
eCSE_Feature_Bass = 0x05,
|
||||
eCSE_Feature_Mid = 0x06,
|
||||
eCSE_Feature_Treble = 0x07,
|
||||
eCSE_Feature_GEQ = 0x08,
|
||||
eCSE_Feature_AGC = 0x09,
|
||||
eCSE_Feature_Delay = 0x0a,
|
||||
eCSE_Feature_BassBoost = 0x0b,
|
||||
eCSE_Feature_Loudness = 0x0c,
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& avDevice );
|
||||
};
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
class FunctionBlockEnhancedMixer: public FunctionBlock
|
||||
{
|
||||
public:
|
||||
FunctionBlockEnhancedMixer( AVC::Subunit& subunit,
|
||||
AVC::function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
AVC::no_of_input_plugs_t nrOfInputPlugs,
|
||||
AVC::no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose );
|
||||
FunctionBlockEnhancedMixer();
|
||||
FunctionBlockEnhancedMixer( const FunctionBlockEnhancedMixer& rhs );
|
||||
virtual ~FunctionBlockEnhancedMixer();
|
||||
|
||||
virtual bool discover();
|
||||
|
||||
virtual const char* getName();
|
||||
|
||||
protected:
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& avDevice );
|
||||
};
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
class FunctionBlockProcessing: public FunctionBlock
|
||||
{
|
||||
public:
|
||||
FunctionBlockProcessing( AVC::Subunit& subunit,
|
||||
AVC::function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
AVC::no_of_input_plugs_t nrOfInputPlugs,
|
||||
AVC::no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose );
|
||||
FunctionBlockProcessing( const FunctionBlockProcessing& rhs );
|
||||
FunctionBlockProcessing();
|
||||
virtual ~FunctionBlockProcessing();
|
||||
|
||||
virtual const char* getName();
|
||||
|
||||
protected:
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& avDevice );
|
||||
};
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
class FunctionBlockCodec: public FunctionBlock
|
||||
{
|
||||
public:
|
||||
FunctionBlockCodec(AVC::Subunit& subunit,
|
||||
AVC::function_block_id_t id,
|
||||
ESpecialPurpose purpose,
|
||||
AVC::no_of_input_plugs_t nrOfInputPlugs,
|
||||
AVC::no_of_output_plugs_t nrOfOutputPlugs,
|
||||
int verbose);
|
||||
FunctionBlockCodec( const FunctionBlockCodec& rhs );
|
||||
FunctionBlockCodec();
|
||||
virtual ~FunctionBlockCodec();
|
||||
|
||||
virtual const char* getName();
|
||||
|
||||
protected:
|
||||
virtual bool serializeChild( std::string basePath,
|
||||
Util::IOSerialize& ser ) const;
|
||||
virtual bool deserializeChild( std::string basePath,
|
||||
Util::IODeserialize& deser,
|
||||
AvDevice& avDevice );
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bebob/bebob_mixer.h"
|
||||
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
#include "bebob/bebob_avdevice_subunit.h"
|
||||
|
||||
#include "libavc/audiosubunit/avc_function_block.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
|
||||
#include "libcontrol/BasicElements.h"
|
||||
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
#include "libieee1394/configrom.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
template <class T>
|
||||
bool from_string(T& t,
|
||||
const std::string& s,
|
||||
std::ios_base& (*f)(std::ios_base&))
|
||||
{
|
||||
std::istringstream iss(s);
|
||||
return !(iss >> f >> t).fail();
|
||||
}
|
||||
|
||||
IMPL_DEBUG_MODULE( Mixer, Mixer, DEBUG_LEVEL_NORMAL );
|
||||
|
||||
Mixer::Mixer(Device &d)
|
||||
: Control::Container(&d)
|
||||
, m_device(d)
|
||||
{
|
||||
addElementForAllFunctionBlocks();
|
||||
if (!d.addElement(this)) {
|
||||
debugWarning("Could not add myself to Control::Container\n");
|
||||
}
|
||||
}
|
||||
|
||||
Mixer::~Mixer() {
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,"Unregistering from Control::Container...\n");
|
||||
if (!m_device.deleteElement(this)) {
|
||||
debugWarning("Could not delete myself from Control::Container\n");
|
||||
}
|
||||
|
||||
// delete all our elements since we should have created
|
||||
// them ourselves.
|
||||
for ( Control::ElementVectorIterator it = m_Children.begin();
|
||||
it != m_Children.end();
|
||||
++it )
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,"deleting %s...\n", (*it)->getName().c_str());
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Mixer::deleteElement(Element *e)
|
||||
{
|
||||
if (Control::Container::deleteElement(e)) {
|
||||
delete e;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Mixer::clearElements() {
|
||||
// delete all our elements since we should have created
|
||||
// them ourselves.
|
||||
for ( Control::ElementVectorIterator it = m_Children.begin();
|
||||
it != m_Children.end();
|
||||
++it )
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
m_Children.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename FBType, typename MixerType>
|
||||
bool
|
||||
Mixer::addElementForFunctionBlock(FBType& b)
|
||||
{
|
||||
Control::Element *e = new MixerType(*this, b);
|
||||
if (!e) {
|
||||
debugError("Control element creation failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
e->setVerboseLevel(getDebugLevel());
|
||||
return Control::Container::addElement(e);
|
||||
}
|
||||
|
||||
bool
|
||||
Mixer::addElementForAllFunctionBlocks() {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,"Adding elements for functionblocks...\n");
|
||||
|
||||
bool retval = true;
|
||||
|
||||
BeBoB::SubunitAudio *asu =
|
||||
dynamic_cast<BeBoB::SubunitAudio *>(m_device.getAudioSubunit(0));
|
||||
|
||||
if(asu == NULL) {
|
||||
debugWarning("No BeBoB audio subunit found\n");
|
||||
return false;
|
||||
}
|
||||
FunctionBlockVector functions=asu->getFunctionBlocks();
|
||||
|
||||
for ( FunctionBlockVector::iterator it = functions.begin();
|
||||
it != functions.end();
|
||||
++it )
|
||||
{
|
||||
FunctionBlock *pfb = *it;
|
||||
FunctionBlockSelector *ps;
|
||||
FunctionBlockFeature *pf;
|
||||
FunctionBlockEnhancedMixer *pm;
|
||||
|
||||
if ((ps = dynamic_cast<FunctionBlockSelector *>(pfb))) {
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "FB is a SelectorFunctionBlock\n");
|
||||
retval = addElementForFunctionBlock<FunctionBlockSelector, MixerFBSelector>(*ps);
|
||||
} else if ((pf = dynamic_cast<FunctionBlockFeature *>(pfb))) {
|
||||
// We might should check if really both feature function
|
||||
// blocks exists and only then announce them. The FA-101,
|
||||
// FA-66 and the Ref BCO Audio5 do have both.
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "FB is a FeatureFunctionBlock\n");
|
||||
retval = addElementForFunctionBlock<FunctionBlockFeature, MixerFBFeatureVolume>(*pf);
|
||||
retval &= addElementForFunctionBlock<FunctionBlockFeature, MixerFBFeatureLRBalance>(*pf);
|
||||
} else if ((pm = dynamic_cast<FunctionBlockEnhancedMixer *>(pfb))) {
|
||||
// All BeBoB devices lock the mixer feature function
|
||||
// block. The AV/C model for this mixer is just to
|
||||
// complex and the BridgeCo guys decided to use the above
|
||||
// function feature blocks (level and balance) to achive
|
||||
// the same.
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "FB is a FunctionBlockEnhancedMixer\n");
|
||||
retval = addElementForFunctionBlock<FunctionBlockEnhancedMixer, EnhancedMixerFBFeature>(*pm);
|
||||
}
|
||||
|
||||
if (!retval) {
|
||||
std::ostringstream ostrm;
|
||||
ostrm << (*it)->getName() << " " << (int)((*it)->getId());
|
||||
|
||||
debugWarning("Failed to add element for function block %s\n",
|
||||
ostrm.str().c_str());
|
||||
};
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --- element implementation classes
|
||||
|
||||
MixerFBFeatureVolume::MixerFBFeatureVolume(Mixer& parent, FunctionBlockFeature& s)
|
||||
: Control::Continuous(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_Slave(s)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << s.getName() << "_Volume_" << (int)(s.getId());
|
||||
|
||||
Control::Continuous::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for " << s.getName() << "_Volume " << (int)(s.getId());
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for " << s.getName() << "_Volume " << (int)(s.getId());
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
MixerFBFeatureVolume::~MixerFBFeatureVolume()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MixerFBFeatureVolume::setValue(double v)
|
||||
{
|
||||
return setValue(0, v);
|
||||
}
|
||||
|
||||
bool
|
||||
MixerFBFeatureVolume::setValue(int idx, double v)
|
||||
{
|
||||
int volume=(int)v;
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Set feature volume %d to %d...\n",
|
||||
m_Slave.getId(), volume);
|
||||
return m_Parent.getParent().setFeatureFBVolumeCurrent(m_Slave.getId(), idx, volume);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureVolume::getValue()
|
||||
{
|
||||
return getValue(0);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureVolume::getValue(int idx)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature volume %d...\n",
|
||||
m_Slave.getId());
|
||||
|
||||
return m_Parent.getParent().getFeatureFBVolumeCurrent(m_Slave.getId(), idx);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureVolume::getMinimum()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature minimum volume %d...\n",
|
||||
m_Slave.getId());
|
||||
|
||||
return m_Parent.getParent().getFeatureFBVolumeMinimum(m_Slave.getId(), 0);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureVolume::getMaximum()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature maximum volume %d...\n",
|
||||
m_Slave.getId());
|
||||
|
||||
return m_Parent.getParent().getFeatureFBVolumeMaximum(m_Slave.getId(), 0);
|
||||
}
|
||||
|
||||
// --- element implementation classes
|
||||
|
||||
MixerFBFeatureLRBalance::MixerFBFeatureLRBalance(Mixer& parent, FunctionBlockFeature& s)
|
||||
: Control::Continuous(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_Slave(s)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << s.getName() << "_LRBalance_" << (int)(s.getId());
|
||||
|
||||
Control::Continuous::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for " << s.getName() << "_LRBalance " << (int)(s.getId());
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for " << s.getName() << "_LRBalance " << (int)(s.getId());
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
MixerFBFeatureLRBalance::~MixerFBFeatureLRBalance()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MixerFBFeatureLRBalance::setValue(double v)
|
||||
{
|
||||
return setValue(0, v);
|
||||
}
|
||||
|
||||
bool
|
||||
MixerFBFeatureLRBalance::setValue(int idx, double v)
|
||||
{
|
||||
int volume=(int)v;
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Set feature balance %d to %d...\n",
|
||||
m_Slave.getId(), volume);
|
||||
return m_Parent.getParent().setFeatureFBLRBalanceCurrent(m_Slave.getId(), idx, volume);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureLRBalance::getValue()
|
||||
{
|
||||
return getValue(0);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureLRBalance::getValue(int idx)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature balance %d...\n",
|
||||
m_Slave.getId());
|
||||
|
||||
return m_Parent.getParent().getFeatureFBLRBalanceCurrent(m_Slave.getId(), idx);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureLRBalance::getMinimum()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature balance volume %d...\n",
|
||||
m_Slave.getId());
|
||||
|
||||
return m_Parent.getParent().getFeatureFBLRBalanceMinimum(m_Slave.getId(), 0);
|
||||
}
|
||||
|
||||
double
|
||||
MixerFBFeatureLRBalance::getMaximum()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get feature maximum balance %d...\n",
|
||||
m_Slave.getId());
|
||||
|
||||
return m_Parent.getParent().getFeatureFBLRBalanceMaximum(m_Slave.getId(), 0);
|
||||
}
|
||||
|
||||
// --- element implementation classes
|
||||
|
||||
/*
|
||||
* This function is named with 'EnhancedMixer' but current implementation is
|
||||
* for 'Processing'. There is several reasons.
|
||||
* There is no way to distinguish 'EnhancedMixer' from 'Processing', the
|
||||
* former is an extension of 'Processing' in AV/C audio subunit command.
|
||||
* The limitation of parameter of Continuous dbus interface. The ffado
|
||||
* developer considered to change the type of interface but it's not
|
||||
* reasonable in a point of cost/effect.
|
||||
* As of Oct 2013, the FFADO developers confirm only M-Audio BeBoB devices uses
|
||||
* this command to control mixer. No other devices use it. M-Audio BeBoB
|
||||
* devices can be controlled by single type 'Processing' command even if
|
||||
* they can be controlled by both single and multi type.
|
||||
*/
|
||||
EnhancedMixerFBFeature::EnhancedMixerFBFeature(Mixer& parent, FunctionBlockEnhancedMixer& s)
|
||||
: Control::Continuous(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_Slave(s)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << s.getName() << "_" << (int)(s.getId());
|
||||
|
||||
Control::Continuous::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for " << s.getName() << " " << (int)(s.getId());
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for " << s.getName() << " " << (int)(s.getId());
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
EnhancedMixerFBFeature::~EnhancedMixerFBFeature()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
EnhancedMixerFBFeature::setValue(int idx, double v)
|
||||
{
|
||||
int iPlugNum = (idx >> 8) & 0xF;
|
||||
int iAChNum = (idx >> 4) & 0xF;
|
||||
int oAChNum = (idx >> 0) & 0xF;
|
||||
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Set: FBID: 0x%02X, FBPN: 0x%02X, "
|
||||
"ICN: 0x%02X, OCN: 0x%02X, DATA: 0x%04X\n",
|
||||
m_Slave.getId(), iPlugNum, iAChNum, oAChNum, (int)v);
|
||||
|
||||
return m_Parent.getParent().setProcessingFBMixerSingleCurrent(m_Slave.getId(),
|
||||
iPlugNum, iAChNum, oAChNum,
|
||||
(int)v);
|
||||
}
|
||||
|
||||
double
|
||||
EnhancedMixerFBFeature::getValue(int idx)
|
||||
{
|
||||
int iPlugNum = (idx >> 8) & 0xF;
|
||||
int iAChNum = (idx >> 4) & 0xF;
|
||||
int oAChNum = (idx >> 0) & 0xF;
|
||||
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Set: FBID: 0x%02X, FBPN: 0x%02X, "
|
||||
"ICN: 0x%02X, OCN: 0x%02X\n",
|
||||
m_Slave.getId(), iPlugNum, iAChNum, oAChNum);
|
||||
|
||||
return m_Parent.getParent().getProcessingFBMixerSingleCurrent(m_Slave.getId(),
|
||||
iPlugNum, iAChNum, oAChNum);
|
||||
}
|
||||
|
||||
// --- element implementation classes
|
||||
|
||||
MixerFBSelector::MixerFBSelector(Mixer& parent, FunctionBlockSelector& s)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_Slave(s)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << s.getName() << "_" << (int)(s.getId());
|
||||
|
||||
Control::Discrete::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for " << s.getName() << " " << (int)(s.getId());
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for " << s.getName() << " " << (int)(s.getId());
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
MixerFBSelector::~MixerFBSelector()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MixerFBSelector::setValue(int v)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Set selector %d to %d...\n",
|
||||
m_Slave.getId(), v);
|
||||
return m_Parent.getParent().setSelectorFBValue(m_Slave.getId(), v);
|
||||
}
|
||||
|
||||
int
|
||||
MixerFBSelector::getValue()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,"Get selector %d...\n",
|
||||
m_Slave.getId());
|
||||
return m_Parent.getParent().getSelectorFBValue(m_Slave.getId());
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace BeBoB
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FFAD0_BEBOB_MIXER__
|
||||
#define __FFAD0_BEBOB_MIXER__
|
||||
|
||||
#include "src/debugmodule/debugmodule.h"
|
||||
|
||||
#include "libcontrol/BasicElements.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace BeBoB {
|
||||
|
||||
class Device;
|
||||
class FunctionBlock;
|
||||
class FunctionBlockFeature;
|
||||
class FunctionBlockSelector;
|
||||
class FunctionBlockEnhancedMixer;
|
||||
|
||||
class Mixer
|
||||
: public Control::Container
|
||||
{
|
||||
public:
|
||||
Mixer(Device &d);
|
||||
virtual ~Mixer();
|
||||
|
||||
virtual std::string getName()
|
||||
{ return "Mixer"; };
|
||||
virtual bool setName( std::string n )
|
||||
{ return false; };
|
||||
|
||||
template<typename FBType, typename MixerType> bool addElementForFunctionBlock(FBType& b);
|
||||
bool addElementForAllFunctionBlocks();
|
||||
|
||||
// manipulation of the contained elements
|
||||
bool addElement(Control::Element *)
|
||||
{debugWarning("not allowed"); return false;};
|
||||
bool deleteElement(Control::Element *);
|
||||
bool clearElements();
|
||||
|
||||
Device& getParent()
|
||||
{return m_device;};
|
||||
|
||||
protected:
|
||||
Device& m_device;
|
||||
protected:
|
||||
DECLARE_DEBUG_MODULE;
|
||||
};
|
||||
|
||||
class MixerFBFeatureVolume
|
||||
: public Control::Continuous
|
||||
{
|
||||
public:
|
||||
MixerFBFeatureVolume(Mixer& parent, FunctionBlockFeature&);
|
||||
virtual ~MixerFBFeatureVolume();
|
||||
|
||||
virtual bool setValue(double v);
|
||||
virtual double getValue();
|
||||
virtual bool setValue(int idx, double v);
|
||||
virtual double getValue(int idx);
|
||||
virtual double getMinimum();
|
||||
virtual double getMaximum();
|
||||
|
||||
private:
|
||||
Mixer& m_Parent;
|
||||
FunctionBlockFeature& m_Slave;
|
||||
};
|
||||
|
||||
class MixerFBFeatureLRBalance
|
||||
: public Control::Continuous
|
||||
{
|
||||
public:
|
||||
MixerFBFeatureLRBalance(Mixer& parent, FunctionBlockFeature&);
|
||||
virtual ~MixerFBFeatureLRBalance();
|
||||
|
||||
virtual bool setValue(double v);
|
||||
virtual double getValue();
|
||||
virtual bool setValue(int idx, double v);
|
||||
virtual double getValue(int idx);
|
||||
virtual double getMinimum();
|
||||
virtual double getMaximum();
|
||||
|
||||
private:
|
||||
Mixer& m_Parent;
|
||||
FunctionBlockFeature& m_Slave;
|
||||
};
|
||||
|
||||
class EnhancedMixerFBFeature
|
||||
: public Control::Continuous
|
||||
{
|
||||
public:
|
||||
EnhancedMixerFBFeature(Mixer& parent, FunctionBlockEnhancedMixer&);
|
||||
virtual ~EnhancedMixerFBFeature();
|
||||
|
||||
virtual bool setValue(int idx, double v);
|
||||
virtual double getValue(int idx);
|
||||
|
||||
virtual bool setValue(double v)
|
||||
{return setValue(1, v);};
|
||||
virtual double getValue()
|
||||
{return getValue(1);};
|
||||
|
||||
virtual double getMinimum() {return -32768;};
|
||||
virtual double getMaximum() {return 0;};
|
||||
|
||||
private:
|
||||
Mixer& m_Parent;
|
||||
FunctionBlockEnhancedMixer& m_Slave;
|
||||
};
|
||||
|
||||
class MixerFBSelector
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
MixerFBSelector(Mixer& parent, FunctionBlockSelector&);
|
||||
virtual ~MixerFBSelector();
|
||||
|
||||
virtual bool setValue(int v);
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 0;};
|
||||
|
||||
private:
|
||||
Mixer& m_Parent;
|
||||
FunctionBlockSelector& m_Slave;
|
||||
};
|
||||
|
||||
} // end of namespace BeBoB
|
||||
|
||||
#endif /* __FFAD0_BEBOB_MIXER__ */
|
||||
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "edirol_fa101.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Edirol {
|
||||
|
||||
EdirolFa101Device::EdirolFa101Device( DeviceManager& d,
|
||||
ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d , configRom)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Edirol::EdirolFa101Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
|
||||
m_fixed_clocksource.type = FFADODevice::eCT_Auto;
|
||||
m_fixed_clocksource.valid = true;
|
||||
m_fixed_clocksource.locked = true;
|
||||
m_fixed_clocksource.id = 0;
|
||||
m_fixed_clocksource.slipping = false;
|
||||
m_fixed_clocksource.description = "Device Controlled";
|
||||
|
||||
get1394Service().setFCPResponseFiltering(true);
|
||||
}
|
||||
|
||||
EdirolFa101Device::~EdirolFa101Device()
|
||||
{
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
EdirolFa101Device::getActiveClockSource() {
|
||||
return m_fixed_clocksource;
|
||||
}
|
||||
|
||||
bool
|
||||
EdirolFa101Device::setActiveClockSource(ClockSource s) {
|
||||
// can't change, hence only succeed when identical
|
||||
return s.id == m_fixed_clocksource.id;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
EdirolFa101Device::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_fixed_clocksource);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
EdirolFa101Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::EdirolFa101::EdirolFa101Device\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_EDIROL_FA101_H
|
||||
#define BEBOB_EDIROL_FA101_H
|
||||
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Edirol {
|
||||
|
||||
class EdirolFa101Device : public BeBoB::Device {
|
||||
public:
|
||||
EdirolFa101Device( DeviceManager& d,
|
||||
ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~EdirolFa101Device();
|
||||
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
private:
|
||||
ClockSource m_fixed_clocksource;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "edirol_fa66.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Edirol {
|
||||
|
||||
EdirolFa66Device::EdirolFa66Device( DeviceManager& d,
|
||||
ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d , configRom)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Edirol::EdirolFa66Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
|
||||
m_fixed_clocksource.type = FFADODevice::eCT_Auto;
|
||||
m_fixed_clocksource.valid = true;
|
||||
m_fixed_clocksource.locked = true;
|
||||
m_fixed_clocksource.id = 0;
|
||||
m_fixed_clocksource.slipping = false;
|
||||
m_fixed_clocksource.description = "Device Controlled";
|
||||
}
|
||||
|
||||
EdirolFa66Device::~EdirolFa66Device()
|
||||
{
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
EdirolFa66Device::getActiveClockSource() {
|
||||
return m_fixed_clocksource;
|
||||
}
|
||||
|
||||
bool
|
||||
EdirolFa66Device::setActiveClockSource(ClockSource s) {
|
||||
// can't change, hence only succeed when identical
|
||||
return s.id == m_fixed_clocksource.id;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
EdirolFa66Device::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_fixed_clocksource);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
EdirolFa66Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::EdirolFa66::EdirolFa66Device\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_EDIROL_FA66_H
|
||||
#define BEBOB_EDIROL_FA66_H
|
||||
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Edirol {
|
||||
|
||||
class EdirolFa66Device : public BeBoB::Device {
|
||||
public:
|
||||
EdirolFa66Device( DeviceManager& d,
|
||||
ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~EdirolFa66Device();
|
||||
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
private:
|
||||
ClockSource m_fixed_clocksource;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "quatafire610.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace ESI {
|
||||
|
||||
QuataFireDevice::QuataFireDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d, configRom)
|
||||
{
|
||||
m_fixed_clocksource.type = FFADODevice::eCT_Auto;
|
||||
m_fixed_clocksource.valid = true;
|
||||
m_fixed_clocksource.locked = true;
|
||||
m_fixed_clocksource.id = 0;
|
||||
m_fixed_clocksource.slipping = false;
|
||||
m_fixed_clocksource.description = "Autoselect";
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::ESI::QuataFireDevice (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
}
|
||||
|
||||
QuataFireDevice::~QuataFireDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
QuataFireDevice::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::ESI::QuataFireDevice\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
QuataFireDevice::getActiveClockSource() {
|
||||
return m_fixed_clocksource;
|
||||
}
|
||||
|
||||
bool
|
||||
QuataFireDevice::setActiveClockSource(ClockSource s) {
|
||||
// can't change, hence only succeed when identical
|
||||
return s.id == m_fixed_clocksource.id;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
QuataFireDevice::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_fixed_clocksource);
|
||||
return r;
|
||||
}
|
||||
|
||||
} // ESI
|
||||
} // BeBoB
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_ESI_QUATAFIRE_DEVICE_H
|
||||
#define BEBOB_ESI_QUATAFIRE_DEVICE_H
|
||||
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace ESI {
|
||||
|
||||
class QuataFireDevice : public BeBoB::Device {
|
||||
|
||||
public:
|
||||
QuataFireDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~QuataFireDevice();
|
||||
|
||||
// override these since the quatafire does not support
|
||||
// setting the clock source (it automatically syncs to SPDIF)
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
virtual void showDevice();
|
||||
private:
|
||||
ClockSource m_fixed_clocksource;
|
||||
};
|
||||
|
||||
} // namespace BeBoB
|
||||
} // namespace ESI
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "focusrite_cmd.h"
|
||||
|
||||
#include "libutil/ByteSwap.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
FocusriteVendorDependentCmd::FocusriteVendorDependentCmd(Ieee1394Service& ieee1394service)
|
||||
: VendorDependentCmd( ieee1394service )
|
||||
, m_arg1 ( 0x03 )
|
||||
, m_arg2 ( 0x01 )
|
||||
, m_id ( 0x00000000 )
|
||||
, m_value ( 0x00000000 )
|
||||
{
|
||||
m_companyId=0x00130e;
|
||||
}
|
||||
|
||||
FocusriteVendorDependentCmd::~FocusriteVendorDependentCmd()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
FocusriteVendorDependentCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= VendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_arg1,"FocusriteVendorDependentCmd arg1");
|
||||
result &= se.write(m_arg2,"FocusriteVendorDependentCmd arg2");
|
||||
// FIXME: this is not consistent, we should not have to care about CondSwapFromBus32 here
|
||||
result &= se.write(CondSwapToBus32(m_id),"FocusriteVendorDependentCmd ID");
|
||||
result &= se.write(CondSwapToBus32(m_value),"FocusriteVendorDependentCmd value");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
FocusriteVendorDependentCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= VendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_arg1);
|
||||
result &= de.read(&m_arg2);
|
||||
result &= de.read(&m_id);
|
||||
m_id=CondSwapFromBus32(m_id);
|
||||
result &= de.read(&m_value);
|
||||
m_value=CondSwapFromBus32(m_value);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FOCUSRITEVENDORDEPENDENT_H
|
||||
#define FOCUSRITEVENDORDEPENDENT_H
|
||||
|
||||
#include "libavc/general/avc_generic.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
#include "libavc/general/avc_vendor_dependent_cmd.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
class FocusriteVendorDependentCmd: public AVC::VendorDependentCmd
|
||||
{
|
||||
public:
|
||||
FocusriteVendorDependentCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~FocusriteVendorDependentCmd();
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "FocusriteVendorDependentCmd"; }
|
||||
|
||||
byte_t m_arg1;
|
||||
byte_t m_arg2;
|
||||
|
||||
quadlet_t m_id;
|
||||
quadlet_t m_value;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FOCUSRITEVENDORDEPENDENT_H
|
|
@ -0,0 +1,617 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "focusrite_saffirepro.h"
|
||||
#include "focusrite_cmd.h"
|
||||
|
||||
#include "libutil/ByteSwap.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
FocusriteDevice::FocusriteDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d, configRom)
|
||||
, m_cmd_time_interval( 0 )
|
||||
, m_earliest_next_cmd_time( 0 )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Focusrite::FocusriteDevice (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
addOption(Util::OptionContainer::Option("useAvcForParameters", false));
|
||||
}
|
||||
|
||||
void
|
||||
FocusriteDevice::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Focusrite::FocusriteDevice\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
void
|
||||
FocusriteDevice::setVerboseLevel(int l)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
|
||||
|
||||
BeBoB::Device::setVerboseLevel(l);
|
||||
}
|
||||
|
||||
bool
|
||||
FocusriteDevice::setSpecificValue(uint32_t id, uint32_t v)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Writing parameter address space id 0x%08X (%u), data: 0x%08X\n",
|
||||
id, id, v);
|
||||
bool use_avc = false;
|
||||
if(!getOption("useAvcForParameters", use_avc)) {
|
||||
debugWarning("Could not retrieve useAvcForParameters parameter, defaulting to false\n");
|
||||
}
|
||||
|
||||
// rate control
|
||||
ffado_microsecs_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
|
||||
if(m_cmd_time_interval && (m_earliest_next_cmd_time > now)) {
|
||||
ffado_microsecs_t wait = m_earliest_next_cmd_time - now;
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Rate control... %" PRIu64 "\n", wait );
|
||||
Util::SystemTimeSource::SleepUsecRelative(wait);
|
||||
}
|
||||
m_earliest_next_cmd_time = now + m_cmd_time_interval;
|
||||
|
||||
if (use_avc) {
|
||||
return setSpecificValueAvc(id, v);
|
||||
} else {
|
||||
return setSpecificValueARM(id, v);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FocusriteDevice::getSpecificValue(uint32_t id, uint32_t *v)
|
||||
{
|
||||
bool retval;
|
||||
bool use_avc = false;
|
||||
if(!getOption("useAvcForParameters", use_avc)) {
|
||||
debugWarning("Could not retrieve useAvcForParameters parameter, defaulting to false\n");
|
||||
}
|
||||
|
||||
// rate control
|
||||
ffado_microsecs_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
|
||||
if(m_cmd_time_interval && (m_earliest_next_cmd_time > now)) {
|
||||
ffado_microsecs_t wait = m_earliest_next_cmd_time - now;
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Rate control... %" PRIu64 "\n", wait );
|
||||
Util::SystemTimeSource::SleepUsecRelative(wait);
|
||||
}
|
||||
m_earliest_next_cmd_time = now + m_cmd_time_interval;
|
||||
|
||||
// execute
|
||||
if (use_avc) {
|
||||
retval = getSpecificValueAvc(id, v);
|
||||
} else {
|
||||
retval = getSpecificValueARM(id, v);
|
||||
}
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,"Read parameter address space id 0x%08X (%u): %08X\n", id, id, *v);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// The AV/C methods to set parameters
|
||||
bool
|
||||
FocusriteDevice::setSpecificValueAvc(uint32_t id, uint32_t v)
|
||||
{
|
||||
|
||||
FocusriteVendorDependentCmd cmd( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Control );
|
||||
cmd.setNodeId( getConfigRom().getNodeId() );
|
||||
cmd.setSubunitType( AVC::eST_Unit );
|
||||
cmd.setSubunitId( 0xff );
|
||||
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
// cmd.setVerbose( DEBUG_LEVEL_VERY_VERBOSE );
|
||||
|
||||
cmd.m_id=id;
|
||||
cmd.m_value=v;
|
||||
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "FocusriteVendorDependentCmd info command failed\n" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FocusriteDevice::getSpecificValueAvc(uint32_t id, uint32_t *v)
|
||||
{
|
||||
|
||||
FocusriteVendorDependentCmd cmd( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Status );
|
||||
cmd.setNodeId( getConfigRom().getNodeId() );
|
||||
cmd.setSubunitType( AVC::eST_Unit );
|
||||
cmd.setSubunitId( 0xff );
|
||||
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
// cmd.setVerbose( DEBUG_LEVEL_VERY_VERBOSE );
|
||||
|
||||
cmd.m_id=id;
|
||||
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "FocusriteVendorDependentCmd info command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
*v=cmd.m_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The ARM methods to set parameters
|
||||
bool
|
||||
FocusriteDevice::setSpecificValueARM(uint32_t id, uint32_t v)
|
||||
{
|
||||
fb_quadlet_t data = v;
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing parameter address space id 0x%08X (%u), data: 0x%08X\n",
|
||||
id, id, data);
|
||||
|
||||
fb_nodeaddr_t addr = FR_PARAM_SPACE_START + (id * 4);
|
||||
fb_nodeid_t nodeId = getNodeId() | 0xFFC0;
|
||||
|
||||
if(!get1394Service().write_quadlet( nodeId, addr, CondSwapToBus32(data) ) ) {
|
||||
debugError("Could not write to node 0x%04X addr 0x%012" PRIX64 "\n", nodeId, addr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FocusriteDevice::getSpecificValueARM(uint32_t id, uint32_t *v)
|
||||
{
|
||||
fb_quadlet_t result;
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading parameter address space id 0x%08X\n", id);
|
||||
|
||||
fb_nodeaddr_t addr = FR_PARAM_SPACE_START + (id * 4);
|
||||
fb_nodeid_t nodeId = getNodeId() | 0xFFC0;
|
||||
|
||||
if(!get1394Service().read_quadlet( nodeId, addr, &result ) ) {
|
||||
debugError("Could not read from node 0x%04X addr 0x%012" PRIX64 "\n", nodeId, addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
result = CondSwapFromBus32(result);
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", result);
|
||||
|
||||
*v = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
FocusriteDevice::convertDefToSr( uint32_t def ) {
|
||||
switch(def) {
|
||||
case FOCUSRITE_CMD_SAMPLERATE_44K1: return 44100;
|
||||
case FOCUSRITE_CMD_SAMPLERATE_48K: return 48000;
|
||||
case FOCUSRITE_CMD_SAMPLERATE_88K2: return 88200;
|
||||
case FOCUSRITE_CMD_SAMPLERATE_96K: return 96000;
|
||||
case FOCUSRITE_CMD_SAMPLERATE_176K4: return 176400;
|
||||
case FOCUSRITE_CMD_SAMPLERATE_192K: return 192000;
|
||||
default:
|
||||
debugWarning("Unsupported samplerate def: %08X\n", def);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
FocusriteDevice::convertSrToDef( int sr ) {
|
||||
switch(sr) {
|
||||
case 44100: return FOCUSRITE_CMD_SAMPLERATE_44K1;
|
||||
case 48000: return FOCUSRITE_CMD_SAMPLERATE_48K;
|
||||
case 88200: return FOCUSRITE_CMD_SAMPLERATE_88K2;
|
||||
case 96000: return FOCUSRITE_CMD_SAMPLERATE_96K;
|
||||
case 176400: return FOCUSRITE_CMD_SAMPLERATE_176K4;
|
||||
case 192000: return FOCUSRITE_CMD_SAMPLERATE_192K;
|
||||
default:
|
||||
debugWarning("Unsupported samplerate: %d\n", sr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// --- element implementation classes
|
||||
|
||||
BinaryControl::BinaryControl(FocusriteDevice& parent, int id, int bit)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
, m_cmd_bit ( bit )
|
||||
{}
|
||||
BinaryControl::BinaryControl(FocusriteDevice& parent, int id, int bit,
|
||||
std::string name, std::string label, std::string descr)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
, m_cmd_bit ( bit )
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(descr);
|
||||
}
|
||||
|
||||
bool
|
||||
BinaryControl::setValue(int v)
|
||||
{
|
||||
uint32_t reg;
|
||||
uint32_t old_reg;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_reg=reg;
|
||||
if (v) {
|
||||
reg |= (1<<m_cmd_bit);
|
||||
} else {
|
||||
reg &= ~(1<<m_cmd_bit);
|
||||
}
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for id %d to %d (reg: 0x%08X => 0x%08X)\n",
|
||||
m_cmd_id, v, old_reg, reg);
|
||||
|
||||
if ( !m_Parent.setSpecificValue(m_cmd_id, reg) ) {
|
||||
debugError( "setSpecificValue failed\n" );
|
||||
return false;
|
||||
} else return true;
|
||||
}
|
||||
|
||||
int
|
||||
BinaryControl::getValue()
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
bool val= (reg & (1<<m_cmd_bit)) != 0;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d: reg: 0x%08X, result=%d\n",
|
||||
m_cmd_id, reg, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// --- element implementation classes
|
||||
|
||||
VolumeControl::VolumeControl(FocusriteDevice& parent, int id)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
{}
|
||||
VolumeControl::VolumeControl(FocusriteDevice& parent, int id,
|
||||
std::string name, std::string label, std::string descr)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(descr);
|
||||
}
|
||||
|
||||
bool
|
||||
VolumeControl::setValue(int v)
|
||||
{
|
||||
if (v>0x07FFF) v=0x07FFF;
|
||||
else if (v<0) v=0;
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for id %d to %d\n",
|
||||
m_cmd_id, v);
|
||||
|
||||
if ( !m_Parent.setSpecificValue(m_cmd_id, v) ) {
|
||||
debugError( "setSpecificValue failed\n" );
|
||||
return false;
|
||||
} else return true;
|
||||
}
|
||||
|
||||
int
|
||||
VolumeControl::getValue()
|
||||
{
|
||||
uint32_t val=0;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, &val) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d = %d\n",
|
||||
m_cmd_id, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
MeteringControl::MeteringControl(FocusriteDevice& parent, int id)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
{}
|
||||
MeteringControl::MeteringControl(FocusriteDevice& parent, int id,
|
||||
std::string name, std::string label, std::string descr)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(descr);
|
||||
}
|
||||
|
||||
int
|
||||
MeteringControl::getValue()
|
||||
{
|
||||
uint32_t val=0;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, &val) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d = %d\n",
|
||||
m_cmd_id, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// reg control
|
||||
RegisterControl::RegisterControl(FocusriteDevice& parent)
|
||||
: Control::Register(&parent)
|
||||
, m_Parent(parent)
|
||||
{}
|
||||
RegisterControl::RegisterControl(FocusriteDevice& parent,
|
||||
std::string name, std::string label, std::string descr)
|
||||
: Control::Register(&parent)
|
||||
, m_Parent(parent)
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(descr);
|
||||
}
|
||||
|
||||
bool
|
||||
RegisterControl::setValue(uint64_t addr, uint64_t v)
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for addr %" PRIu64 " to %" PRIu64 "\n",
|
||||
addr, v);
|
||||
|
||||
if ( !m_Parent.setSpecificValue(addr, v) ) {
|
||||
debugError( "setSpecificValue failed\n" );
|
||||
return false;
|
||||
} else return true;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
RegisterControl::getValue(uint64_t addr)
|
||||
{
|
||||
uint32_t val=0;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(addr, &val) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %" PRIu64 " = %u\n",
|
||||
addr, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// low resolution volume control
|
||||
VolumeControlLowRes::VolumeControlLowRes(FocusriteDevice& parent, int id, int shift)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
, m_bit_shift( shift )
|
||||
{}
|
||||
VolumeControlLowRes::VolumeControlLowRes(FocusriteDevice& parent, int id, int shift,
|
||||
std::string name, std::string label, std::string descr)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
, m_bit_shift( shift )
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(descr);
|
||||
}
|
||||
|
||||
bool
|
||||
VolumeControlLowRes::setValue(int v)
|
||||
{
|
||||
uint32_t reg;
|
||||
uint32_t old_reg;
|
||||
|
||||
if (v>0xFF) v=0xFF;
|
||||
else if (v<0) v=0;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_reg=reg;
|
||||
reg &= ~(0xFF<<m_bit_shift);
|
||||
reg |= (v<<m_bit_shift);
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for id %d to %d, shift %d (reg: 0x%08X => 0x%08X)\n",
|
||||
m_cmd_id, v, m_bit_shift, old_reg, reg);
|
||||
|
||||
if ( !m_Parent.setSpecificValue(m_cmd_id, reg) ) {
|
||||
debugError( "setSpecificValue failed\n" );
|
||||
return false;
|
||||
} else return true;
|
||||
}
|
||||
|
||||
int
|
||||
VolumeControlLowRes::getValue()
|
||||
{
|
||||
uint32_t val, reg;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, ®) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
val = (reg & 0xFF)>>m_bit_shift;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d: reg: 0x%08X, result=%d\n",
|
||||
m_cmd_id, reg, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// hardware dial control
|
||||
DialPositionControl::DialPositionControl(FocusriteDevice& parent, int id, int shift)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
, m_shift ( shift )
|
||||
{}
|
||||
DialPositionControl::DialPositionControl(FocusriteDevice& parent, int id, int shift,
|
||||
std::string name, std::string label, std::string descr)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_cmd_id ( id )
|
||||
, m_shift ( shift )
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(descr);
|
||||
}
|
||||
|
||||
int
|
||||
DialPositionControl::getValue()
|
||||
{
|
||||
uint32_t val=0;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_cmd_id, &val) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
if (m_shift > 0) {
|
||||
val = val >> m_shift;
|
||||
} else if (m_shift < 0) {
|
||||
val = val << -m_shift;
|
||||
}
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for %d = %d\n",
|
||||
m_cmd_id, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// Saffire pro matrix mixer element
|
||||
FocusriteMatrixMixer::FocusriteMatrixMixer(FocusriteDevice& p)
|
||||
: Control::MatrixMixer(&p, "MatrixMixer")
|
||||
, m_Parent(p)
|
||||
{
|
||||
}
|
||||
|
||||
FocusriteMatrixMixer::FocusriteMatrixMixer(FocusriteDevice& p,std::string n)
|
||||
: Control::MatrixMixer(&p, n)
|
||||
, m_Parent(p)
|
||||
{
|
||||
}
|
||||
|
||||
void FocusriteMatrixMixer::addSignalInfo(std::vector<struct sSignalInfo> &target,
|
||||
std::string name, std::string label, std::string descr)
|
||||
{
|
||||
struct sSignalInfo s;
|
||||
s.name=name;
|
||||
s.label=label;
|
||||
s.description=descr;
|
||||
|
||||
target.push_back(s);
|
||||
}
|
||||
|
||||
void FocusriteMatrixMixer::setCellInfo(int row, int col, int addr, bool valid)
|
||||
{
|
||||
struct sCellInfo c;
|
||||
c.row=row;
|
||||
c.col=col;
|
||||
c.valid=valid;
|
||||
c.address=addr;
|
||||
|
||||
m_CellInfo.at(row).at(col) = c;
|
||||
}
|
||||
|
||||
void FocusriteMatrixMixer::show()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Focusrite Matrix mixer\n");
|
||||
}
|
||||
|
||||
std::string FocusriteMatrixMixer::getRowName( const int row )
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "name for row %d is %s\n",
|
||||
row, m_RowInfo.at(row).name.c_str());
|
||||
return m_RowInfo.at(row).name;
|
||||
}
|
||||
|
||||
std::string FocusriteMatrixMixer::getColName( const int col )
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "name for col %d is %s\n",
|
||||
col, m_ColInfo.at(col).name.c_str());
|
||||
return m_ColInfo.at(col).name;
|
||||
}
|
||||
|
||||
int FocusriteMatrixMixer::canWrite( const int row, const int col )
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "canWrite for row %d col %d is %d\n",
|
||||
row, col, m_CellInfo.at(row).at(col).valid);
|
||||
return m_CellInfo.at(row).at(col).valid;
|
||||
}
|
||||
|
||||
double FocusriteMatrixMixer::setValue( const int row, const int col, const double val )
|
||||
{
|
||||
int32_t v = (int32_t)val;
|
||||
struct sCellInfo c = m_CellInfo.at(row).at(col);
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "setValue for id %d row %d col %d to %lf (%d)\n",
|
||||
c.address, row, col, val, v);
|
||||
|
||||
if (v>0x07FFF) v=0x07FFF;
|
||||
else if (v<0) v=0;
|
||||
|
||||
if ( !m_Parent.setSpecificValue(c.address, v) ) {
|
||||
debugError( "setSpecificValue failed\n" );
|
||||
return false;
|
||||
} else return true;
|
||||
}
|
||||
|
||||
double FocusriteMatrixMixer::getValue( const int row, const int col )
|
||||
{
|
||||
struct sCellInfo c=m_CellInfo.at(row).at(col);
|
||||
uint32_t val=0;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(c.address, &val) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
} else {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "getValue for id %d row %d col %d = %u\n",
|
||||
c.address, row, col, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
int FocusriteMatrixMixer::getRowCount( )
|
||||
{
|
||||
return m_RowInfo.size();
|
||||
}
|
||||
|
||||
int FocusriteMatrixMixer::getColCount( )
|
||||
{
|
||||
return m_ColInfo.size();
|
||||
}
|
||||
|
||||
|
||||
} // Focusrite
|
||||
} // BeBoB
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_FOCUSRITE_GENERIC_DEVICE_H
|
||||
#define BEBOB_FOCUSRITE_GENERIC_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
#include "libcontrol/BasicElements.h"
|
||||
#include "libcontrol/MatrixMixer.h"
|
||||
|
||||
#include "libutil/SystemTimeSource.h"
|
||||
|
||||
#define FR_PARAM_SPACE_START 0x000100000000LL
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
class FocusriteDevice;
|
||||
|
||||
class BinaryControl
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
BinaryControl(FocusriteDevice& parent, int id, int bit);
|
||||
BinaryControl(FocusriteDevice& parent, int id, int bit,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(int v);
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 1;};
|
||||
|
||||
private:
|
||||
FocusriteDevice& m_Parent;
|
||||
unsigned int m_cmd_id;
|
||||
unsigned int m_cmd_bit;
|
||||
};
|
||||
|
||||
class VolumeControl
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
VolumeControl(FocusriteDevice& parent, int id);
|
||||
VolumeControl(FocusriteDevice& parent, int id,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(int v);
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 0x07FFF;};
|
||||
|
||||
private:
|
||||
FocusriteDevice& m_Parent;
|
||||
unsigned int m_cmd_id;
|
||||
};
|
||||
|
||||
class MeteringControl
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
MeteringControl(FocusriteDevice& parent, int id);
|
||||
MeteringControl(FocusriteDevice& parent, int id,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(int v) {return false;};
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 0x07FFF;};
|
||||
private:
|
||||
FocusriteDevice& m_Parent;
|
||||
unsigned int m_cmd_id;
|
||||
};
|
||||
|
||||
class RegisterControl
|
||||
: public Control::Register
|
||||
{
|
||||
public:
|
||||
RegisterControl(FocusriteDevice& parent);
|
||||
RegisterControl(FocusriteDevice& parent,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(uint64_t addr, uint64_t value);
|
||||
virtual uint64_t getValue(uint64_t addr);
|
||||
|
||||
private:
|
||||
FocusriteDevice& m_Parent;
|
||||
};
|
||||
|
||||
class VolumeControlLowRes
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
VolumeControlLowRes(FocusriteDevice& parent, int id, int shift);
|
||||
VolumeControlLowRes(FocusriteDevice& parent, int id, int shift,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(int v);
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 0x0FF;};
|
||||
private:
|
||||
FocusriteDevice& m_Parent;
|
||||
unsigned int m_cmd_id;
|
||||
unsigned int m_bit_shift;
|
||||
};
|
||||
|
||||
class DialPositionControl
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
DialPositionControl(FocusriteDevice& parent, int id, int shift);
|
||||
DialPositionControl(FocusriteDevice& parent, int id, int shift,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(int v) {return false;};
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 0x07FFF;};
|
||||
private:
|
||||
FocusriteDevice& m_Parent;
|
||||
unsigned int m_cmd_id;
|
||||
int m_shift;
|
||||
};
|
||||
|
||||
class FocusriteMatrixMixer : public Control::MatrixMixer
|
||||
{
|
||||
public:
|
||||
FocusriteMatrixMixer(FocusriteDevice& parent);
|
||||
FocusriteMatrixMixer(FocusriteDevice& parent, std::string n);
|
||||
virtual ~FocusriteMatrixMixer() {};
|
||||
|
||||
virtual void show();
|
||||
|
||||
virtual int getRowCount( );
|
||||
virtual int getColCount( );
|
||||
|
||||
virtual int canWrite( const int, const int );
|
||||
virtual double setValue( const int, const int, const double );
|
||||
virtual double getValue( const int, const int );
|
||||
|
||||
// full map updates are unsupported
|
||||
virtual bool getCoefficientMap(int &) {return false;};
|
||||
virtual bool storeCoefficientMap(int &) {return false;};
|
||||
|
||||
bool hasNames() const { return true; }
|
||||
virtual std::string getRowName( const int );
|
||||
virtual std::string getColName( const int );
|
||||
|
||||
bool canConnect() const { return false; }
|
||||
|
||||
protected:
|
||||
struct sSignalInfo {
|
||||
std::string name;
|
||||
std::string label;
|
||||
std::string description;
|
||||
};
|
||||
struct sCellInfo {
|
||||
int row;
|
||||
int col;
|
||||
// indicates whether a cell can be valid, this
|
||||
// doesn't mean that it is writable. Just that it can be.
|
||||
bool valid;
|
||||
// the address to use when manipulating this cell
|
||||
int address;
|
||||
};
|
||||
|
||||
virtual void init() = 0;
|
||||
virtual void addSignalInfo(std::vector<struct sSignalInfo> &target,
|
||||
std::string name, std::string label, std::string descr);
|
||||
virtual void setCellInfo(int row, int col, int addr, bool valid);
|
||||
|
||||
std::vector<struct sSignalInfo> m_RowInfo;
|
||||
std::vector<struct sSignalInfo> m_ColInfo;
|
||||
std::vector< std::vector<struct sCellInfo> > m_CellInfo;
|
||||
|
||||
FocusriteDevice& m_Parent;
|
||||
};
|
||||
|
||||
class FocusriteDevice : public BeBoB::Device {
|
||||
public:
|
||||
FocusriteDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~FocusriteDevice() {};
|
||||
|
||||
virtual void showDevice();
|
||||
virtual void setVerboseLevel(int l);
|
||||
|
||||
public:
|
||||
bool setSpecificValue(uint32_t id, uint32_t v);
|
||||
bool getSpecificValue(uint32_t id, uint32_t *v);
|
||||
|
||||
protected:
|
||||
int convertDefToSr( uint32_t def );
|
||||
uint32_t convertSrToDef( int sr );
|
||||
|
||||
private:
|
||||
bool setSpecificValueAvc(uint32_t id, uint32_t v);
|
||||
bool getSpecificValueAvc(uint32_t id, uint32_t *v);
|
||||
|
||||
bool setSpecificValueARM(uint32_t id, uint32_t v);
|
||||
bool getSpecificValueARM(uint32_t id, uint32_t *v);
|
||||
|
||||
protected:
|
||||
ffado_microsecs_t m_cmd_time_interval;
|
||||
ffado_microsecs_t m_earliest_next_cmd_time;
|
||||
};
|
||||
|
||||
} // namespace Focusrite
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "focusrite_saffire.h"
|
||||
#include "focusrite_cmd.h"
|
||||
|
||||
#include "devicemanager.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
SaffireDevice::SaffireDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
: FocusriteDevice( d, configRom)
|
||||
, m_MixerContainer( NULL )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Focusrite::SaffireDevice (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
|
||||
if(getConfigRom().getGuid() < 0x130e0100040000LL) {
|
||||
m_isSaffireLE = false;
|
||||
} else {
|
||||
m_isSaffireLE = true;
|
||||
}
|
||||
|
||||
// find the configured delay time for this device
|
||||
Util::Configuration &config = d.getConfiguration();
|
||||
int delaytime = 0;
|
||||
if(config.getValueForDeviceSetting(getConfigRom().getNodeVendorId(), getConfigRom().getModelId(), "cmd_interval_time", delaytime)) {
|
||||
m_cmd_time_interval = delaytime;
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting command interval time to %" PRIu64 "\n",
|
||||
m_cmd_time_interval );
|
||||
} else {
|
||||
m_cmd_time_interval = 10000;
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "No command interval time setting found, defaulting to %" PRIu64 "\n",
|
||||
m_cmd_time_interval );
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SaffireDevice::buildMixer()
|
||||
{
|
||||
bool result=true;
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Building a Focusrite Saffire mixer...\n");
|
||||
|
||||
destroyMixer();
|
||||
|
||||
// create the mixer object container
|
||||
m_MixerContainer = new Control::Container(this, "Mixer");
|
||||
|
||||
if (!m_MixerContainer) {
|
||||
debugError("Could not create mixer container...\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_isSaffireLE) {
|
||||
// create control objects for the saffire LE
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_SPDIF_TRANSPARENT, 0,
|
||||
"SpdifTransparent", "S/PDIF Transparent", "S/PDIF Transparent"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_MIDITHRU, 0,
|
||||
"MidiThru", "MIDI Thru", "MIDI Thru"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_SAVE_SETTINGS, 0,
|
||||
"SaveSettings", "Save Settings", "Save Settings"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_HIGH_GAIN_LINE3, 0,
|
||||
"HighGainLine3", "High Gain Line-in 3", "High Gain Line-in 3"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_HIGH_GAIN_LINE4, 0,
|
||||
"HighGainLine4", "High Gain Line-in 4", "High Gain Line-in 4"));
|
||||
|
||||
// output mute controls
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out12Mute", "Out1/2 Mute", "Output 1/2 Mute"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out34Mute", "Out3/4 Mute", "Output 3/4 Mute"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out56Mute", "Out5/6 Mute", "Output 5/6 Mute"));
|
||||
|
||||
// output front panel hw volume control
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out12HwCtrl", "Out1/2 HwCtrl", "Output 1/2 Front Panel Hardware volume control"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out34HwCtrl", "Out3/4 HwCtrl", "Output 3/4 Front Panel Hardware volume control"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out56HwCtrl", "Out5/6 HwCtrl", "Output 5/6 Front Panel Hardware volume control"));
|
||||
|
||||
// dac ignore
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out12DacIgnore", "Out1/2 Dac Ignore", "Output 1/2 Dac Ignore"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out34DacIgnore", "Out3/4 Dac Ignore", "Output 3/4 Dac Ignore"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out56DacIgnore", "Out5/6 Dac Ignore", "Output 5/6 Dac Ignore"));
|
||||
|
||||
// output level controls
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out12Level", "Out1/2 Level", "Output 1/2 Level"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out34Level", "Out3/4 Level", "Output 3/4 Level"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out56Level", "Out5/6 Level", "Output 5/6 Level"));
|
||||
|
||||
} else {
|
||||
// create control objects for the saffire
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_INPUT_SOURCE, 0,
|
||||
"SpdifSwitch", "S/PDIF Switch", "S/PDIF Switch"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_MONO_MODE, 0,
|
||||
"MonoMode", "Mono Mode", "Toggle Mono Mode"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_DEVICE_MODE, 0,
|
||||
"DeviceMode", "Device Mode", "Toggle Device Mode"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_EXTERNAL_LOCK, 0,
|
||||
"ExternalLock", "External Lock", "Has external lock?"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_AUDIO_ON_STATUS, 0,
|
||||
"AudioOnStatus", "Audio On Status", "Audio On Status"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_SAVE_SETTINGS, 0,
|
||||
"SaveSettings", "Save Settings", "Save Settings"));
|
||||
|
||||
// output mute controls
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out12Mute", "Out1/2 Mute", "Output 1/2 Mute"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out34Mute", "Out3/4 Mute", "Output 3/4 Mute"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out56Mute", "Out5/6 Mute", "Output 5/6 Mute"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out78Mute", "Out7/8 Mute", "Output 7/8 Mute"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT910, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE,
|
||||
"Out910Mute", "Out9/10 Mute", "Output 9/10 Mute"));
|
||||
|
||||
// output front panel hw volume control
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out12HwCtrl", "Out1/2 HwCtrl", "Output 1/2 Front Panel Hardware volume control"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out34HwCtrl", "Out3/4 HwCtrl", "Output 3/4 Front Panel Hardware volume control"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out56HwCtrl", "Out5/6 HwCtrl", "Output 5/6 Front Panel Hardware volume control"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL,
|
||||
"Out78HwCtrl", "Out7/8 HwCtrl", "Output 7/8 Front Panel Hardware volume control"));
|
||||
|
||||
// output level dim
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DIM,
|
||||
"Out12Dim", "Out1/2 Dim", "Output 1/2 Level Dim"));
|
||||
|
||||
// dac ignore
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out12DacIgnore", "Out1/2 Dac Ignore", "Output 1/2 Dac Ignore"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out34DacIgnore", "Out3/4 Dac Ignore", "Output 3/4 Dac Ignore"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out56DacIgnore", "Out5/6 Dac Ignore", "Output 5/6 Dac Ignore"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE,
|
||||
"Out78DacIgnore", "Out7/8 Dac Ignore", "Output 7/8 Dac Ignore"));
|
||||
|
||||
// output level controls
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT12, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out12Level", "Out1/2 Level", "Output 1/2 Level"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT34, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out34Level", "Out3/4 Level", "Output 3/4 Level"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT56, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out56Level", "Out5/6 Level", "Output 5/6 Level"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new VolumeControlLowRes(*this,
|
||||
FR_SAFFIRE_CMD_ID_BITFIELD_OUT78, FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC,
|
||||
"Out78Level", "Out7/8 Level", "Output 7/8 Level"));
|
||||
|
||||
result &= m_MixerContainer->addElement(
|
||||
new DialPositionControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_MONITOR_DIAL, 0,
|
||||
"MonitorDial", "Monitor Dial", "Monitor Dial Value"));
|
||||
|
||||
// metering
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_IN1,
|
||||
"MeteringIn1", "Metering Input 1", "Metering on Input 1"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_IN2,
|
||||
"MeteringIn2", "Metering Input 2", "Metering on Input 2"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_IN3,
|
||||
"MeteringIn3", "Metering Input 3", "Metering on Input 3"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_IN4,
|
||||
"MeteringIn4", "Metering Input 4", "Metering on Input 4"));
|
||||
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC1,
|
||||
"MeteringPc1", "Metering PC 1", "Metering on PC Channel 1"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC2,
|
||||
"MeteringPc2", "Metering PC 2", "Metering on PC Channel 2"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC3,
|
||||
"MeteringPc3", "Metering PC 3", "Metering on PC Channel 3"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC4,
|
||||
"MeteringPc4", "Metering PC 4", "Metering on PC Channel 4"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC5,
|
||||
"MeteringPc5", "Metering PC 5", "Metering on PC Channel 5"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC6,
|
||||
"MeteringPc6", "Metering PC 6", "Metering on PC Channel 6"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC7,
|
||||
"MeteringPc7", "Metering PC 7", "Metering on PC Channel 7"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC8,
|
||||
"MeteringPc8", "Metering PC 8", "Metering on PC Channel 8"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC9,
|
||||
"MeteringPc9", "Metering PC 9", "Metering on PC Channel 9"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new MeteringControl(*this,
|
||||
FR_SAFFIRE_CMD_ID_METERING_PC10,
|
||||
"MeteringPc10", "Metering PC 10", "Metering on PC Channel 10"));
|
||||
|
||||
}
|
||||
|
||||
// matrix mix controls
|
||||
if(m_isSaffireLE) {
|
||||
result &= m_MixerContainer->addElement(
|
||||
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_LEMix48, "LEMix48"));
|
||||
|
||||
result &= m_MixerContainer->addElement(
|
||||
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_LEMix96, "LEMix96"));
|
||||
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_SWAP_OUT4_OUT1_48K, 0,
|
||||
"Swap41_48", "Swap41_48", "Swap41_48"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new BinaryControl(*this,
|
||||
FR_SAFFIRELE_CMD_ID_SWAP_OUT4_OUT1_96K, 0,
|
||||
"Swap41_96", "Swap41_96", "Swap41_96"));
|
||||
} else {
|
||||
result &= m_MixerContainer->addElement(
|
||||
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_SaffireStereoMatrixMix, "MatrixMixerStereo"));
|
||||
result &= m_MixerContainer->addElement(
|
||||
new SaffireMatrixMixer(*this, SaffireMatrixMixer::eMMT_SaffireMonoMatrixMix, "MatrixMixerMono"));
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
debugWarning("One or more control elements could not be created.");
|
||||
// clean up those that were created
|
||||
destroyMixer();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addElement(m_MixerContainer)) {
|
||||
debugWarning("Could not register mixer to device\n");
|
||||
// clean up
|
||||
destroyMixer();
|
||||
return false;
|
||||
}
|
||||
|
||||
// add a direct register access element
|
||||
if (!addElement(new RegisterControl(*this, "Register", "Register Access", "Direct register access"))) {
|
||||
debugWarning("Could not create register control element.");
|
||||
// clean up those that were created
|
||||
destroyMixer();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SaffireDevice::destroyMixer()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "destroy mixer...\n");
|
||||
|
||||
if (m_MixerContainer == NULL) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "no mixer to destroy...\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!deleteElement(m_MixerContainer)) {
|
||||
debugError("Mixer present but not registered to the avdevice\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove and delete (as in free) child control elements
|
||||
m_MixerContainer->clearElements(true);
|
||||
delete m_MixerContainer;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
SaffireDevice::getSupportedSamplingFrequencies()
|
||||
{
|
||||
std::vector<int> frequencies;
|
||||
frequencies.push_back(44100);
|
||||
frequencies.push_back(48000);
|
||||
frequencies.push_back(88200);
|
||||
frequencies.push_back(96000);
|
||||
return frequencies;
|
||||
}
|
||||
|
||||
void
|
||||
SaffireDevice::showDevice()
|
||||
{
|
||||
if(m_isSaffireLE) {
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Focusrite::SaffireDevice (Saffire LE)\n");
|
||||
} else {
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Focusrite::SaffireDevice (Saffire)\n");
|
||||
}
|
||||
FocusriteDevice::showDevice();
|
||||
}
|
||||
|
||||
void
|
||||
SaffireDevice::setVerboseLevel(int l)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l );
|
||||
|
||||
FocusriteDevice::setVerboseLevel(l);
|
||||
}
|
||||
|
||||
// Saffire pro matrix mixer element
|
||||
|
||||
SaffireMatrixMixer::SaffireMatrixMixer(SaffireDevice& p,
|
||||
enum eMatrixMixerType type)
|
||||
: FocusriteMatrixMixer(p, "MatrixMixer")
|
||||
, m_type(type)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
SaffireMatrixMixer::SaffireMatrixMixer(SaffireDevice& p,
|
||||
enum eMatrixMixerType type, std::string n)
|
||||
: FocusriteMatrixMixer(p, n)
|
||||
, m_type(type)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void SaffireMatrixMixer::init()
|
||||
{
|
||||
if (m_type==eMMT_SaffireStereoMatrixMix) {
|
||||
m_RowInfo.clear();
|
||||
addSignalInfo(m_RowInfo, "PC910", "PC 9/10", "PC Channel 9/10");
|
||||
addSignalInfo(m_RowInfo, "PC12", "PC 1/2", "PC Channel 1/2");
|
||||
addSignalInfo(m_RowInfo, "PC34", "PC 3/4", "PC Channel 3/4");
|
||||
addSignalInfo(m_RowInfo, "PC56", "PC 5/6", "PC Channel 5/6");
|
||||
addSignalInfo(m_RowInfo, "PC78", "PC 7/8", "PC Channel 7/8");
|
||||
addSignalInfo(m_RowInfo, "IN12", "Input 1/2", "Hardware Inputs 1/2");
|
||||
addSignalInfo(m_RowInfo, "IN34", "Input 3/4", "Hardware Inputs 3/4 (dry / S/PDIF)");
|
||||
addSignalInfo(m_RowInfo, "FX", "Effect return", "Effect return");
|
||||
|
||||
m_ColInfo.clear();
|
||||
addSignalInfo(m_ColInfo, "OUT910", "OUT 9/10", "Output 9/10");
|
||||
addSignalInfo(m_ColInfo, "OUT12", "OUT 1/2", "Output 1/2");
|
||||
addSignalInfo(m_ColInfo, "OUT34", "OUT 3/4", "Output 3/4");
|
||||
addSignalInfo(m_ColInfo, "OUT56", "OUT 5/6", "Output 5/6 (HP1)");
|
||||
addSignalInfo(m_ColInfo, "OUT78", "OUT 7/8", "Output 7/8 (HP2)");
|
||||
|
||||
// init the cell matrix
|
||||
#define FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS 5
|
||||
#define FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_ROWS 8
|
||||
#define FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_OFFSET 0
|
||||
|
||||
std::vector<struct sCellInfo> tmp_cols( FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS );
|
||||
std::vector< std::vector<struct sCellInfo> > tmp_all(FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_ROWS, tmp_cols);
|
||||
m_CellInfo = tmp_all;
|
||||
|
||||
struct sCellInfo c;
|
||||
c.row=-1;
|
||||
c.col=-1;
|
||||
c.valid=false;
|
||||
c.address=0;
|
||||
|
||||
// all cells are valid
|
||||
for (int i=0; i < FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_ROWS; i++) {
|
||||
for (int j=0; j < FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS; j++) {
|
||||
c.row = i;
|
||||
c.col = j;
|
||||
c.valid = true;
|
||||
c.address = FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_OFFSET + c.row * FOCUSRITE_SAFFIRE_STEREO_MATRIXMIX_NB_COLS + c.col;
|
||||
m_CellInfo.at(i).at(j) = c;
|
||||
}
|
||||
}
|
||||
} else if (m_type==eMMT_SaffireMonoMatrixMix) {
|
||||
m_RowInfo.clear();
|
||||
addSignalInfo(m_RowInfo, "IN1", "Input 1", "Hardware Inputs 1");
|
||||
addSignalInfo(m_RowInfo, "IN3", "Input 3", "Hardware Inputs 3");
|
||||
addSignalInfo(m_RowInfo, "FX1", "Effect return 1", "Effect return 1");
|
||||
addSignalInfo(m_RowInfo, "IN2", "Input 2", "Hardware Inputs 2");
|
||||
addSignalInfo(m_RowInfo, "IN4", "Input 4", "Hardware Inputs 4");
|
||||
addSignalInfo(m_RowInfo, "FX2", "Effect return 2", "Effect return 2");
|
||||
addSignalInfo(m_RowInfo, "PC910", "PC 9/10", "PC Channel 9/10");
|
||||
addSignalInfo(m_RowInfo, "PC12", "PC 1/2", "PC Channel 1/2");
|
||||
addSignalInfo(m_RowInfo, "PC34", "PC 3/4", "PC Channel 3/4");
|
||||
addSignalInfo(m_RowInfo, "PC56", "PC 5/6", "PC Channel 5/6");
|
||||
addSignalInfo(m_RowInfo, "PC78", "PC 7/8", "PC Channel 7/8");
|
||||
|
||||
m_ColInfo.clear();
|
||||
addSignalInfo(m_ColInfo, "OUT910", "OUT 9/10", "Output 9/10");
|
||||
addSignalInfo(m_ColInfo, "OUT12", "OUT 1/2", "Output 1/2");
|
||||
addSignalInfo(m_ColInfo, "OUT34", "OUT 3/4", "Output 3/4");
|
||||
addSignalInfo(m_ColInfo, "OUT56", "OUT 5/6", "Output 5/6 (HP1)");
|
||||
addSignalInfo(m_ColInfo, "OUT78", "OUT 7/8", "Output 7/8 (HP2)");
|
||||
|
||||
// init the cell matrix
|
||||
#define FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS 5
|
||||
#define FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_ROWS 11
|
||||
#define FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_OFFSET 0
|
||||
|
||||
std::vector<struct sCellInfo> tmp_cols( FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS );
|
||||
std::vector< std::vector<struct sCellInfo> > tmp_all(FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_ROWS, tmp_cols);
|
||||
m_CellInfo = tmp_all;
|
||||
|
||||
struct sCellInfo c;
|
||||
c.row=-1;
|
||||
c.col=-1;
|
||||
c.valid=false;
|
||||
c.address=0;
|
||||
|
||||
// all cells are valid
|
||||
for (int i=0; i < FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_ROWS; i++) {
|
||||
for (int j=0; j < FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS; j++) {
|
||||
c.row = i;
|
||||
c.col = j;
|
||||
c.valid = true;
|
||||
c.address = FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_OFFSET + c.row * FOCUSRITE_SAFFIRE_MONO_MATRIXMIX_NB_COLS + c.col;
|
||||
m_CellInfo.at(i).at(j) = c;
|
||||
}
|
||||
}
|
||||
} else if (m_type == eMMT_LEMix48) {
|
||||
addSignalInfo(m_RowInfo, "IN1", "Input 1", "Analog Input 1");
|
||||
addSignalInfo(m_RowInfo, "IN2", "Input 2", "Analog Input 2");
|
||||
addSignalInfo(m_RowInfo, "IN3", "Input 3", "Analog Input 3");
|
||||
addSignalInfo(m_RowInfo, "IN4", "Input 4", "Analog Input 4");
|
||||
addSignalInfo(m_RowInfo, "SPDIFL", "SPDIF L", "S/PDIF Left Input");
|
||||
addSignalInfo(m_RowInfo, "SPDIFR", "SPDIF R", "S/PDIF Right Input");
|
||||
|
||||
addSignalInfo(m_RowInfo, "PC1", "PC 1", "PC Channel 1");
|
||||
addSignalInfo(m_RowInfo, "PC2", "PC 2", "PC Channel 2");
|
||||
addSignalInfo(m_RowInfo, "PC3", "PC 3", "PC Channel 3");
|
||||
addSignalInfo(m_RowInfo, "PC4", "PC 4", "PC Channel 4");
|
||||
addSignalInfo(m_RowInfo, "PC5", "PC 5", "PC Channel 5");
|
||||
addSignalInfo(m_RowInfo, "PC6", "PC 6", "PC Channel 6");
|
||||
addSignalInfo(m_RowInfo, "PC7", "PC 7", "PC Channel 7");
|
||||
addSignalInfo(m_RowInfo, "PC8", "PC 8", "PC Channel 8");
|
||||
|
||||
addSignalInfo(m_ColInfo, "OUT1", "OUT 1", "Output 1");
|
||||
addSignalInfo(m_ColInfo, "OUT2", "OUT 2", "Output 2");
|
||||
addSignalInfo(m_ColInfo, "OUT3", "OUT 3", "Output 3");
|
||||
addSignalInfo(m_ColInfo, "OUT4", "OUT 4", "Output 4");
|
||||
|
||||
// init the cell matrix
|
||||
#define FOCUSRITE_SAFFIRELE_48KMIX_NB_COLS 4
|
||||
#define FOCUSRITE_SAFFIRELE_48KMIX_NB_ROWS 14
|
||||
|
||||
std::vector<struct sCellInfo> tmp_cols( FOCUSRITE_SAFFIRELE_48KMIX_NB_COLS );
|
||||
std::vector< std::vector<struct sCellInfo> > tmp_all(FOCUSRITE_SAFFIRELE_48KMIX_NB_ROWS,tmp_cols);
|
||||
m_CellInfo = tmp_all;
|
||||
|
||||
struct sCellInfo c;
|
||||
c.row=-1;
|
||||
c.col=-1;
|
||||
c.valid=false;
|
||||
c.address=0;
|
||||
|
||||
for (int i=0;i<FOCUSRITE_SAFFIRELE_48KMIX_NB_ROWS;i++) {
|
||||
for (int j=0;j<FOCUSRITE_SAFFIRELE_48KMIX_NB_COLS;j++) {
|
||||
m_CellInfo.at(i).at(j) = c;
|
||||
}
|
||||
}
|
||||
|
||||
// now set the cells that are valid
|
||||
setCellInfo(0,0,FR_SAFFIRELE_CMD_ID_IN1_TO_OUT1, true);
|
||||
setCellInfo(0,1,FR_SAFFIRELE_CMD_ID_IN1_TO_OUT2, true);
|
||||
setCellInfo(0,2,FR_SAFFIRELE_CMD_ID_IN1_TO_OUT3, true);
|
||||
setCellInfo(0,3,FR_SAFFIRELE_CMD_ID_IN1_TO_OUT4, true);
|
||||
setCellInfo(1,0,FR_SAFFIRELE_CMD_ID_IN2_TO_OUT1, true);
|
||||
setCellInfo(1,1,FR_SAFFIRELE_CMD_ID_IN2_TO_OUT2, true);
|
||||
setCellInfo(1,2,FR_SAFFIRELE_CMD_ID_IN2_TO_OUT3, true);
|
||||
setCellInfo(1,3,FR_SAFFIRELE_CMD_ID_IN2_TO_OUT4, true);
|
||||
setCellInfo(2,0,FR_SAFFIRELE_CMD_ID_IN3_TO_OUT1, true);
|
||||
setCellInfo(2,1,FR_SAFFIRELE_CMD_ID_IN3_TO_OUT2, true);
|
||||
setCellInfo(2,2,FR_SAFFIRELE_CMD_ID_IN3_TO_OUT3, true);
|
||||
setCellInfo(2,3,FR_SAFFIRELE_CMD_ID_IN3_TO_OUT4, true);
|
||||
setCellInfo(3,0,FR_SAFFIRELE_CMD_ID_IN4_TO_OUT1, true);
|
||||
setCellInfo(3,1,FR_SAFFIRELE_CMD_ID_IN4_TO_OUT2, true);
|
||||
setCellInfo(3,2,FR_SAFFIRELE_CMD_ID_IN4_TO_OUT3, true);
|
||||
setCellInfo(3,3,FR_SAFFIRELE_CMD_ID_IN4_TO_OUT4, true);
|
||||
|
||||
setCellInfo(4,0,FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT1, true);
|
||||
setCellInfo(4,1,FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT2, true);
|
||||
setCellInfo(4,2,FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT3, true);
|
||||
setCellInfo(4,3,FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT4, true);
|
||||
setCellInfo(5,0,FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT1, true);
|
||||
setCellInfo(5,1,FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT2, true);
|
||||
setCellInfo(5,2,FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT3, true);
|
||||
setCellInfo(5,3,FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT4, true);
|
||||
setCellInfo(6,0,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT1, true);
|
||||
setCellInfo(6,1,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT2, true);
|
||||
setCellInfo(6,2,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT3, true);
|
||||
setCellInfo(6,3,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT4, true);
|
||||
setCellInfo(7,0,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT1, true);
|
||||
setCellInfo(7,1,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT2, true);
|
||||
setCellInfo(7,2,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT3, true);
|
||||
setCellInfo(7,3,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT4, true);
|
||||
setCellInfo(8,0,FR_SAFFIRELE_CMD_ID_PC3_TO_OUT1, true);
|
||||
setCellInfo(8,1,FR_SAFFIRELE_CMD_ID_PC3_TO_OUT2, true);
|
||||
setCellInfo(8,2,FR_SAFFIRELE_CMD_ID_PC3_TO_OUT3, true);
|
||||
setCellInfo(8,3,FR_SAFFIRELE_CMD_ID_PC3_TO_OUT4, true);
|
||||
setCellInfo(9,0,FR_SAFFIRELE_CMD_ID_PC4_TO_OUT1, true);
|
||||
setCellInfo(9,1,FR_SAFFIRELE_CMD_ID_PC4_TO_OUT2, true);
|
||||
setCellInfo(9,2,FR_SAFFIRELE_CMD_ID_PC4_TO_OUT3, true);
|
||||
setCellInfo(9,3,FR_SAFFIRELE_CMD_ID_PC4_TO_OUT4, true);
|
||||
setCellInfo(10,0,FR_SAFFIRELE_CMD_ID_PC5_TO_OUT1, true);
|
||||
setCellInfo(10,1,FR_SAFFIRELE_CMD_ID_PC5_TO_OUT2, true);
|
||||
setCellInfo(10,2,FR_SAFFIRELE_CMD_ID_PC5_TO_OUT3, true);
|
||||
setCellInfo(10,3,FR_SAFFIRELE_CMD_ID_PC5_TO_OUT4, true);
|
||||
setCellInfo(11,0,FR_SAFFIRELE_CMD_ID_PC6_TO_OUT1, true);
|
||||
setCellInfo(11,1,FR_SAFFIRELE_CMD_ID_PC6_TO_OUT2, true);
|
||||
setCellInfo(11,2,FR_SAFFIRELE_CMD_ID_PC6_TO_OUT3, true);
|
||||
setCellInfo(11,3,FR_SAFFIRELE_CMD_ID_PC6_TO_OUT4, true);
|
||||
setCellInfo(12,0,FR_SAFFIRELE_CMD_ID_PC7_TO_OUT1, true);
|
||||
setCellInfo(12,1,FR_SAFFIRELE_CMD_ID_PC7_TO_OUT2, true);
|
||||
setCellInfo(12,2,FR_SAFFIRELE_CMD_ID_PC7_TO_OUT3, true);
|
||||
setCellInfo(12,3,FR_SAFFIRELE_CMD_ID_PC7_TO_OUT4, true);
|
||||
setCellInfo(13,0,FR_SAFFIRELE_CMD_ID_PC8_TO_OUT1, true);
|
||||
setCellInfo(13,1,FR_SAFFIRELE_CMD_ID_PC8_TO_OUT2, true);
|
||||
setCellInfo(13,2,FR_SAFFIRELE_CMD_ID_PC8_TO_OUT3, true);
|
||||
setCellInfo(13,3,FR_SAFFIRELE_CMD_ID_PC8_TO_OUT4, true);
|
||||
|
||||
} else if (m_type == eMMT_LEMix96) {
|
||||
addSignalInfo(m_RowInfo, "IN1", "Input 1", "Analog Input 1");
|
||||
addSignalInfo(m_RowInfo, "IN2", "Input 2", "Analog Input 2");
|
||||
addSignalInfo(m_RowInfo, "IN3", "Input 3", "Analog Input 3");
|
||||
addSignalInfo(m_RowInfo, "IN4", "Input 4", "Analog Input 4");
|
||||
addSignalInfo(m_RowInfo, "SPDIFL", "SPDIF L", "S/PDIF Left Input");
|
||||
addSignalInfo(m_RowInfo, "SPDIFR", "SPDIF R", "S/PDIF Right Input");
|
||||
|
||||
addSignalInfo(m_RowInfo, "PC1", "PC 1", "PC Channel 1");
|
||||
addSignalInfo(m_RowInfo, "PC2", "PC 2", "PC Channel 2");
|
||||
addSignalInfo(m_RowInfo, "PC3", "PC 3", "PC Channel 3");
|
||||
addSignalInfo(m_RowInfo, "PC4", "PC 4", "PC Channel 4");
|
||||
addSignalInfo(m_RowInfo, "PC5", "PC 5", "PC Channel 5");
|
||||
addSignalInfo(m_RowInfo, "PC6", "PC 6", "PC Channel 6");
|
||||
addSignalInfo(m_RowInfo, "PC7", "PC 7", "PC Channel 7");
|
||||
addSignalInfo(m_RowInfo, "PC8", "PC 8", "PC Channel 8");
|
||||
addSignalInfo(m_RowInfo, "RECMIXRETURN", "RECMIXRETURN", "Record mix (mono) return");
|
||||
|
||||
addSignalInfo(m_ColInfo, "OUT1", "OUT 1", "Output 1");
|
||||
addSignalInfo(m_ColInfo, "OUT2", "OUT 2", "Output 2");
|
||||
addSignalInfo(m_ColInfo, "OUT3", "OUT 3", "Output 3");
|
||||
addSignalInfo(m_ColInfo, "OUT4", "OUT 4", "Output 4");
|
||||
addSignalInfo(m_ColInfo, "RECMIX", "RECMIX", "Record mix (mono)");
|
||||
|
||||
// init the cell matrix
|
||||
#define FOCUSRITE_SAFFIRELE_96KMIX_NB_COLS 5
|
||||
#define FOCUSRITE_SAFFIRELE_96KMIX_NB_ROWS 15
|
||||
|
||||
std::vector<struct sCellInfo> tmp_cols( FOCUSRITE_SAFFIRELE_96KMIX_NB_COLS );
|
||||
std::vector< std::vector<struct sCellInfo> > tmp_all(FOCUSRITE_SAFFIRELE_96KMIX_NB_ROWS,tmp_cols);
|
||||
m_CellInfo = tmp_all;
|
||||
|
||||
struct sCellInfo c;
|
||||
c.row=-1;
|
||||
c.col=-1;
|
||||
c.valid=false;
|
||||
c.address=0;
|
||||
|
||||
for (int i=0;i<FOCUSRITE_SAFFIRELE_96KMIX_NB_ROWS;i++) {
|
||||
for (int j=0;j<FOCUSRITE_SAFFIRELE_96KMIX_NB_COLS;j++) {
|
||||
m_CellInfo.at(i).at(j) = c;
|
||||
}
|
||||
}
|
||||
|
||||
// now set the cells that are valid
|
||||
setCellInfo(0,4,FR_SAFFIRELE_CMD_ID_IN1_TO_RECMIX_96K, true);
|
||||
setCellInfo(1,4,FR_SAFFIRELE_CMD_ID_IN2_TO_RECMIX_96K, true);
|
||||
setCellInfo(2,4,FR_SAFFIRELE_CMD_ID_IN3_TO_RECMIX_96K, true);
|
||||
setCellInfo(3,4,FR_SAFFIRELE_CMD_ID_IN4_TO_RECMIX_96K, true);
|
||||
setCellInfo(4,4,FR_SAFFIRELE_CMD_ID_SPDIF1_TO_RECMIX_96K, true);
|
||||
setCellInfo(5,4,FR_SAFFIRELE_CMD_ID_SPDIF2_TO_RECMIX_96K, true);
|
||||
|
||||
setCellInfo(14,0,FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT1_96K, true);
|
||||
setCellInfo(14,1,FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT2_96K, true);
|
||||
setCellInfo(14,2,FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT3_96K, true);
|
||||
setCellInfo(14,3,FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT4_96K, true);
|
||||
|
||||
setCellInfo(7,0,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT1_96K, true);
|
||||
setCellInfo(7,1,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT2_96K, true);
|
||||
setCellInfo(7,2,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT3_96K, true);
|
||||
setCellInfo(7,3,FR_SAFFIRELE_CMD_ID_PC1_TO_OUT4_96K, true);
|
||||
setCellInfo(8,0,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT1_96K, true);
|
||||
setCellInfo(8,1,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT2_96K, true);
|
||||
setCellInfo(8,2,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT3_96K, true);
|
||||
setCellInfo(8,3,FR_SAFFIRELE_CMD_ID_PC2_TO_OUT4_96K, true);
|
||||
} else {
|
||||
debugError("Invalid mixer type\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SaffireMatrixMixer::show()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Saffire Matrix mixer type %d\n", m_type);
|
||||
}
|
||||
|
||||
} // Focusrite
|
||||
} // BeBoB
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_FOCUSRITE_SAFFIRE_DEVICE_H
|
||||
#define BEBOB_FOCUSRITE_SAFFIRE_DEVICE_H
|
||||
|
||||
#include "focusrite_generic.h"
|
||||
|
||||
#include "libcontrol/BasicElements.h"
|
||||
#include "libcontrol/MatrixMixer.h"
|
||||
|
||||
// -- Original Saffire --
|
||||
|
||||
// no need for control id's, we can directly compute the addresses of the matrix mixer
|
||||
/*
|
||||
|
||||
MIXER LAYOUT ():
|
||||
|
||||
OFFSET: 30
|
||||
|
||||
|-- Out9/10--| |-- Out1/2 --| |-- Out3/4 --| |-- Out5/6 --| |-- Out7/8 --|
|
||||
P5 0: 0/ 0 1: 110/ 110 2: 0/ 0 3: 0/ 0 4: 0/ 0
|
||||
P1 5: 0/ 0 6:32767/32767 7: 0/ 0 8: 0/ 0 9: 0/ 0
|
||||
P2 10: 0/ 0 11: 0/ 0 12:32767/32767 13: 0/ 0 14: 0/ 0
|
||||
P3 15: 0/ 0 16: 0/ 0 17: 0/ 0 18:32767/32767 19: 0/ 0
|
||||
P4 20: 0/ 0 21: 0/ 0 22: 0/ 0 23: 0/ 0 24:32767/32767
|
||||
R1 25: 0/ 0 26: 0/ 0 27: 0/ 0 28: 0/ 0 29: 0/ 0
|
||||
R2 30: 0/ 0 31: 0/ 0 32: 0/ 0 33: 0/ 0 34: 0/ 0
|
||||
Fx 35: 0/ 0 36: 0/ 0 37: 0/ 0 38: 0/ 0 39: 0/ 0
|
||||
|
||||
P5: DAW ch 9/10
|
||||
P1: DAW ch 1/2
|
||||
P2: DAW ch 3/4
|
||||
P3: DAW ch 5/6
|
||||
P4: DAW ch 7/8
|
||||
R1: HW INPUT ch 1/2 / Reverb ch 1
|
||||
R2: HW INPUT ch 3/4 / Reverb ch 2
|
||||
Fx: reverb/fx return? / input mix
|
||||
|
||||
*/
|
||||
|
||||
// the control ID's
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_OUT12 55
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_OUT34 56
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_OUT56 57
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_OUT78 58
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_OUT910 59
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DIM 24
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_BIT_MUTE 25
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DACIGNORE 26
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_BIT_HWCTRL 27
|
||||
#define FR_SAFFIRE_CMD_ID_BITFIELD_BIT_DAC 0
|
||||
|
||||
// other stuff
|
||||
#define FR_SAFFIRE_CMD_ID_MONITOR_DIAL 61
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_INPUT_SOURCE 62
|
||||
#define FR_SAFFIRE_CMD_ID_INPUT_SOURCE_SPDIF 1
|
||||
#define FR_SAFFIRE_CMD_ID_INPUT_SOURCE_ANALOG 0
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_MONO_MODE 63
|
||||
#define FR_SAFFIRE_CMD_ID_MONO_MODE_STEREO 0
|
||||
#define FR_SAFFIRE_CMD_ID_MONO_MODE_MONO 1
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_IN1 64
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_IN2 65
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_IN3 66
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_IN4 67
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC1 68
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC2 69
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC3 70
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC4 71
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC5 72
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC6 73
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC7 74
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC8 75
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC9 76
|
||||
#define FR_SAFFIRE_CMD_ID_METERING_PC10 77
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_DEVICE_MODE 78
|
||||
#define FR_SAFFIRE_CMD_ID_DEVICE_MODE_NORMAL 0
|
||||
#define FR_SAFFIRE_CMD_ID_DEVICE_MODE_SCARD 1
|
||||
|
||||
#define FR_SAFFIRE_CMD_ID_EXTERNAL_LOCK 79
|
||||
#define FR_SAFFIRE_CMD_ID_AUDIO_ON_STATUS 80
|
||||
#define FR_SAFFIRE_CMD_ID_SAVE_SETTINGS 82
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_DSP_REVISION 1022
|
||||
#define FR_SAFFIRELE_CMD_ID_DSP_VERSION 1023
|
||||
|
||||
// -- Saffire LE --
|
||||
|
||||
// The ID's for the hardware input matrix mixer
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT1 0
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT3 1
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT2 2
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT4 3
|
||||
#define FR_SAFFIRELE_CMD_ID_PC3_TO_OUT1 4
|
||||
#define FR_SAFFIRELE_CMD_ID_PC3_TO_OUT3 5
|
||||
#define FR_SAFFIRELE_CMD_ID_PC3_TO_OUT2 6
|
||||
#define FR_SAFFIRELE_CMD_ID_PC3_TO_OUT4 7
|
||||
#define FR_SAFFIRELE_CMD_ID_PC5_TO_OUT1 8
|
||||
#define FR_SAFFIRELE_CMD_ID_PC5_TO_OUT3 9
|
||||
#define FR_SAFFIRELE_CMD_ID_PC5_TO_OUT2 10
|
||||
#define FR_SAFFIRELE_CMD_ID_PC5_TO_OUT4 11
|
||||
#define FR_SAFFIRELE_CMD_ID_PC7_TO_OUT1 12
|
||||
#define FR_SAFFIRELE_CMD_ID_PC7_TO_OUT3 13
|
||||
#define FR_SAFFIRELE_CMD_ID_PC7_TO_OUT2 14
|
||||
#define FR_SAFFIRELE_CMD_ID_PC7_TO_OUT4 15
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT1 16
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT3 17
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT2 18
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT4 19
|
||||
#define FR_SAFFIRELE_CMD_ID_PC4_TO_OUT1 20
|
||||
#define FR_SAFFIRELE_CMD_ID_PC4_TO_OUT3 21
|
||||
#define FR_SAFFIRELE_CMD_ID_PC4_TO_OUT2 22
|
||||
#define FR_SAFFIRELE_CMD_ID_PC4_TO_OUT4 23
|
||||
#define FR_SAFFIRELE_CMD_ID_PC6_TO_OUT1 24
|
||||
#define FR_SAFFIRELE_CMD_ID_PC6_TO_OUT3 25
|
||||
#define FR_SAFFIRELE_CMD_ID_PC6_TO_OUT2 26
|
||||
#define FR_SAFFIRELE_CMD_ID_PC6_TO_OUT4 27
|
||||
#define FR_SAFFIRELE_CMD_ID_PC8_TO_OUT1 28
|
||||
#define FR_SAFFIRELE_CMD_ID_PC8_TO_OUT3 29
|
||||
#define FR_SAFFIRELE_CMD_ID_PC8_TO_OUT2 30
|
||||
#define FR_SAFFIRELE_CMD_ID_PC8_TO_OUT4 31
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_IN1_TO_OUT1 32
|
||||
#define FR_SAFFIRELE_CMD_ID_IN1_TO_OUT3 33
|
||||
#define FR_SAFFIRELE_CMD_ID_IN1_TO_OUT2 34
|
||||
#define FR_SAFFIRELE_CMD_ID_IN1_TO_OUT4 35
|
||||
#define FR_SAFFIRELE_CMD_ID_IN3_TO_OUT1 36
|
||||
#define FR_SAFFIRELE_CMD_ID_IN3_TO_OUT3 37
|
||||
#define FR_SAFFIRELE_CMD_ID_IN3_TO_OUT2 38
|
||||
#define FR_SAFFIRELE_CMD_ID_IN3_TO_OUT4 39
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT1 40
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT3 41
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT2 42
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF1_TO_OUT4 43
|
||||
#define FR_SAFFIRELE_CMD_ID_IN2_TO_OUT1 44
|
||||
#define FR_SAFFIRELE_CMD_ID_IN2_TO_OUT3 45
|
||||
#define FR_SAFFIRELE_CMD_ID_IN2_TO_OUT2 46
|
||||
#define FR_SAFFIRELE_CMD_ID_IN2_TO_OUT4 47
|
||||
#define FR_SAFFIRELE_CMD_ID_IN4_TO_OUT1 48
|
||||
#define FR_SAFFIRELE_CMD_ID_IN4_TO_OUT3 49
|
||||
#define FR_SAFFIRELE_CMD_ID_IN4_TO_OUT2 50
|
||||
#define FR_SAFFIRELE_CMD_ID_IN4_TO_OUT4 51
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT1 52
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT3 53
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT2 54
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF2_TO_OUT4 55
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_SWAP_OUT4_OUT1_48K 64
|
||||
|
||||
// 96kHz controls
|
||||
#define FR_SAFFIRELE_CMD_ID_IN1_TO_RECMIX_96K 66
|
||||
#define FR_SAFFIRELE_CMD_ID_IN3_TO_RECMIX_96K 67
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF1_TO_RECMIX_96K 68
|
||||
#define FR_SAFFIRELE_CMD_ID_IN2_TO_RECMIX_96K 69
|
||||
#define FR_SAFFIRELE_CMD_ID_IN4_TO_RECMIX_96K 70
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF2_TO_RECMIX_96K 71
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT1_96K 72
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT1_96K 73
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT1_96K 74
|
||||
#define FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT3_96K 75
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT3_96K 76
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT3_96K 77
|
||||
#define FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT2_96K 78
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT2_96K 79
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT2_96K 80
|
||||
#define FR_SAFFIRELE_CMD_ID_RECMIX_TO_OUT4_96K 81
|
||||
#define FR_SAFFIRELE_CMD_ID_PC1_TO_OUT4_96K 82
|
||||
#define FR_SAFFIRELE_CMD_ID_PC2_TO_OUT4_96K 83
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_SWAP_OUT4_OUT1_96K 84
|
||||
|
||||
// metering
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_IN1 90
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_IN3 91
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_SPDIF1 92
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_IN2 93
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_IN4 94
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_SPDIF2 95
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT1 96
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT3 97
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT5 98
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT7 99
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT2 100
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT4 101
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT6 102
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_OUT8 103
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_PC1 104
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_PC3 105
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_PC2 106
|
||||
#define FR_SAFFIRELE_CMD_ID_METERING_PC4 107
|
||||
|
||||
// other stuff
|
||||
#define FR_SAFFIRELE_CMD_ID_HIGH_GAIN_LINE3 85
|
||||
#define FR_SAFFIRELE_CMD_ID_HIGH_GAIN_LINE4 86
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_OUT12 87
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_OUT34 88
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_OUT56 89
|
||||
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DIM 24
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_MUTE 25
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DACIGNORE 26
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_HWCTRL 27
|
||||
#define FR_SAFFIRELE_CMD_ID_BITFIELD_BIT_DAC 0
|
||||
|
||||
#define FR_SAFFIRELE_CMD_ID_EXT_CLOCK_LOCK 108
|
||||
#define FR_SAFFIRELE_CMD_ID_AUDIO_ON 109
|
||||
#define FR_SAFFIRELE_CMD_ID_SAVE_SETTINGS 110
|
||||
#define FR_SAFFIRELE_CMD_ID_MIDITHRU 111
|
||||
#define FR_SAFFIRELE_CMD_ID_SPDIF_TRANSPARENT 112
|
||||
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
class SaffireDevice;
|
||||
|
||||
class SaffireMatrixMixer : public FocusriteMatrixMixer
|
||||
{
|
||||
public:
|
||||
enum eMatrixMixerType {
|
||||
eMMT_SaffireStereoMatrixMix,
|
||||
eMMT_SaffireMonoMatrixMix,
|
||||
eMMT_LEMix48,
|
||||
eMMT_LEMix96,
|
||||
};
|
||||
public:
|
||||
SaffireMatrixMixer(SaffireDevice& parent, enum eMatrixMixerType type);
|
||||
SaffireMatrixMixer(SaffireDevice& parent, enum eMatrixMixerType type, std::string n);
|
||||
virtual ~SaffireMatrixMixer() {};
|
||||
|
||||
virtual void show();
|
||||
|
||||
protected:
|
||||
void init();
|
||||
enum eMatrixMixerType m_type;
|
||||
};
|
||||
|
||||
class SaffireDevice : public FocusriteDevice {
|
||||
public:
|
||||
SaffireDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~SaffireDevice() {};
|
||||
|
||||
virtual void showDevice();
|
||||
virtual void setVerboseLevel(int l);
|
||||
|
||||
virtual bool buildMixer();
|
||||
virtual bool destroyMixer();
|
||||
virtual std::vector<int> getSupportedSamplingFrequencies();
|
||||
|
||||
private:
|
||||
Control::Container *m_MixerContainer;
|
||||
bool m_isSaffireLE;
|
||||
};
|
||||
|
||||
} // namespace Focusrite
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_FOCUSRITE_SAFFIRE_PRO_DEVICE_H
|
||||
#define BEBOB_FOCUSRITE_SAFFIRE_PRO_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "focusrite_generic.h"
|
||||
|
||||
#include "libcontrol/BasicElements.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// MIXER ID's
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN1_TO_IMIXL 0
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN1_TO_IMIXR 1
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN2_TO_IMIXL 2
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN2_TO_IMIXR 3
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN3_TO_IMIXL 4
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN3_TO_IMIXR 5
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN4_TO_IMIXL 6
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN4_TO_IMIXR 7
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN5_TO_IMIXL 8
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN5_TO_IMIXR 9
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN6_TO_IMIXL 10
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN6_TO_IMIXR 11
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN7_TO_IMIXL 12
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN7_TO_IMIXR 13
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN8_TO_IMIXL 14
|
||||
#define FR_SAFFIREPRO_CMD_ID_AN8_TO_IMIXR 15
|
||||
#define FR_SAFFIREPRO_CMD_ID_SPDIFL_TO_IMIXL 16
|
||||
#define FR_SAFFIREPRO_CMD_ID_SPDIFL_TO_IMIXR 17
|
||||
#define FR_SAFFIREPRO_CMD_ID_SPDIFR_TO_IMIXL 18
|
||||
#define FR_SAFFIREPRO_CMD_ID_SPDIFR_TO_IMIXR 19
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT11_TO_IMIXL 20
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT11_TO_IMIXR 21
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT12_TO_IMIXL 22
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT12_TO_IMIXR 23
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT13_TO_IMIXL 24
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT13_TO_IMIXR 25
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT14_TO_IMIXL 26
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT14_TO_IMIXR 27
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT15_TO_IMIXL 28
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT15_TO_IMIXR 29
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT16_TO_IMIXL 30
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT16_TO_IMIXR 31
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT17_TO_IMIXL 32
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT17_TO_IMIXR 33
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT18_TO_IMIXL 34
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT18_TO_IMIXR 35
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT21_TO_IMIXL 36
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT21_TO_IMIXR 37
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT22_TO_IMIXL 38
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT22_TO_IMIXR 39
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT23_TO_IMIXL 40
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT23_TO_IMIXR 41
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT24_TO_IMIXL 42
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT24_TO_IMIXR 43
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT25_TO_IMIXL 44
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT25_TO_IMIXR 45
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT26_TO_IMIXL 46
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT26_TO_IMIXR 47
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT27_TO_IMIXL 48
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT27_TO_IMIXR 49
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT28_TO_IMIXL 50
|
||||
#define FR_SAFFIREPRO_CMD_ID_ADAT28_TO_IMIXR 51
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC1_TO_OUT1 52
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC2_TO_OUT2 54
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX1_TO_OUT1 53
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX2_TO_OUT2 55
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC1_TO_OUT3 56
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC2_TO_OUT4 59
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC3_TO_OUT3 57
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC4_TO_OUT4 60
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX1_TO_OUT3 58
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX2_TO_OUT4 61
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC1_TO_OUT5 62
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC2_TO_OUT6 65
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC5_TO_OUT5 63
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC6_TO_OUT6 66
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX1_TO_OUT5 64
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX2_TO_OUT6 67
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC1_TO_OUT7 68
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC2_TO_OUT8 71
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC7_TO_OUT7 69
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC8_TO_OUT8 72
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX1_TO_OUT7 70
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX2_TO_OUT8 73
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC1_TO_OUT9 74
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC2_TO_OUT10 77
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC9_TO_OUT9 75
|
||||
#define FR_SAFFIREPRO_CMD_ID_PC10_TO_OUT10 78
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX1_TO_OUT9 76
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIX2_TO_OUT10 79
|
||||
|
||||
// SAMPLERATE related ID's
|
||||
#define FR_SAFFIREPRO_CMD_ID_SAMPLERATE 84
|
||||
#define FR_SAFFIREPRO_CMD_ID_SAMPLERATE_NOREBOOT 115
|
||||
|
||||
#define FOCUSRITE_CMD_SAMPLERATE_44K1 1
|
||||
#define FOCUSRITE_CMD_SAMPLERATE_48K 2
|
||||
#define FOCUSRITE_CMD_SAMPLERATE_88K2 3
|
||||
#define FOCUSRITE_CMD_SAMPLERATE_96K 4
|
||||
#define FOCUSRITE_CMD_SAMPLERATE_176K4 5
|
||||
#define FOCUSRITE_CMD_SAMPLERATE_192K 6
|
||||
|
||||
// OTHER CONFIG id's
|
||||
#define FR_SAFFIREPRO_CMD_ID_BITFIELD_OUT12 80
|
||||
#define FR_SAFFIREPRO_CMD_ID_BITFIELD_OUT34 81
|
||||
#define FR_SAFFIREPRO_CMD_ID_BITFIELD_OUT56 82
|
||||
#define FR_SAFFIREPRO_CMD_ID_BITFIELD_OUT78 83
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_BITFIELD_BIT_MUTE 24
|
||||
#define FR_SAFFIREPRO_CMD_BITFIELD_BIT_DAC_IGNORE 25
|
||||
#define FR_SAFFIREPRO_CMD_BITFIELD_BIT_HWCTRL 26
|
||||
#define FR_SAFFIREPRO_CMD_BITFIELD_BIT_PAD 27
|
||||
#define FR_SAFFIREPRO_CMD_BITFIELD_BIT_DIM 28
|
||||
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_SWITCH_CONFIG 85
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_DIM12 (1<<0)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_DIM34 (1<<1)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_DIM56 (1<<2)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_DIM78 (1<<3)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_MUTE12 (1<<4)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_MUTE34 (1<<5)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_MUTE56 (1<<6)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_MUTE78 (1<<7)
|
||||
#define FR_SAFFIREPRO_CMD_SWITCH_CONFIG_MUTE910 (1<<8)
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_MONITOR_DIAL 86
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIM_INDICATOR 87
|
||||
#define FR_SAFFIREPRO_CMD_ID_MUTE_INDICATOR 88
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_EXT_CLOCK_LOCK 89
|
||||
#define FR_SAFFIREPRO_CMD_ID_AUDIO_ON 90
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_USE_HIGHVOLTAGE_RAIL 91
|
||||
#define FR_SAFFIREPRO_CMD_ID_USING_HIGHVOLTAGE_RAIL 92
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_SYNC_CONFIG_MASK 0x000000FF
|
||||
#define FR_SAFFIREPRO_CMD_ID_SYNC_LOCK_MASK 0x0000FF00
|
||||
#define FR_SAFFIREPRO_CMD_ID_SYNC_CONFIG 93
|
||||
#define FR_SAFFIREPRO_CMD_SYNC_CONFIG_INTERNAL 0
|
||||
#define FR_SAFFIREPRO_CMD_SYNC_CONFIG_SPDIF 2
|
||||
#define FR_SAFFIREPRO_CMD_SYNC_CONFIG_ADAT1 3
|
||||
#define FR_SAFFIREPRO_CMD_SYNC_CONFIG_ADAT2 4
|
||||
#define FR_SAFFIREPRO_CMD_SYNC_CONFIG_WORDCLOCK 5
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_DEVICE_NAME_1 94
|
||||
#define FR_SAFFIREPRO_CMD_ID_DEVICE_NAME_2 95
|
||||
#define FR_SAFFIREPRO_CMD_ID_DEVICE_NAME_3 96
|
||||
#define FR_SAFFIREPRO_CMD_ID_DEVICE_NAME_4 97
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PHANTOM14 98
|
||||
#define FR_SAFFIREPRO_CMD_ID_PHANTOM58 99
|
||||
#define FR_SAFFIREPRO_CMD_ID_INSERT1 100
|
||||
#define FR_SAFFIREPRO_CMD_ID_INSERT2 101
|
||||
|
||||
// led flashing
|
||||
#define FR_SAFFIREPRO_CMD_ID_FLASH_LED 102
|
||||
#define FR_SAFFIREPRO_CMD_FLASH_MASK_SECS 0x00FF
|
||||
#define FR_SAFFIREPRO_CMD_FLASH_MASK_FREQ 0xFF00
|
||||
#define FR_SAFFIREPRO_CMD_SET_FLASH_SECS(reg, secs) \
|
||||
(((reg) & ~FR_SAFFIREPRO_CMD_FLASH_MASK_SECS) | \
|
||||
(((secs) & 0xFF)))
|
||||
#define FR_SAFFIREPRO_CMD_GET_FLASH_SECS(reg) \
|
||||
((reg) & FR_SAFFIREPRO_CMD_FLASH_MASK_SECS)
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_SET_FLASH_FREQ(reg, freq) \
|
||||
(((reg) & ~FR_SAFFIREPRO_CMD_FLASH_MASK_FREQ) | \
|
||||
(((freq) & 0xFF) << 8))
|
||||
#define FR_SAFFIREPRO_CMD_GET_FLASH_FREQ(reg) \
|
||||
((reg) & FR_SAFFIREPRO_CMD_FLASH_MASK_FREQ)
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_AC3_PASSTHROUGH 103
|
||||
#define FR_SAFFIREPRO_CMD_ID_MIDI_TRU 104
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_ENABLE_SPDIF_INPUT 105
|
||||
#define FR_SAFFIREPRO_CMD_ID_ENABLE_ADAT1_INPUT 106
|
||||
#define FR_SAFFIREPRO_CMD_ID_ENABLE_ADAT2_INPUT 107
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_SAVE_SETTINGS 108
|
||||
#define FR_SAFFIREPRO_CMD_ID_REBOOT 109
|
||||
#define FR_SAFFIREPRO_CMD_REBOOT_CODE 0xA5A5
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PLAYBACK_COUNT 110
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_REC_OK 0
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_PBK_OK 1
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_RX_READY 2
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_STANDALONE 3
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_SPDIFIN_ON (1<<8)
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_SPDIFIN_ERR (1<<9)
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_ADAT1IN_ON (1<<16)
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_ADAT1IN_ERR (1<<17)
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_ADAT2IN_ON (1<<24)
|
||||
#define FR_SAFFIREPRO_CMD_PLAYBACK_COUNT_ADAT2IN_ERR (1<<25)
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_STANDALONE_MODE 111
|
||||
#define FR_SAFFIREPRO_CMD_ID_AVC_MODEL 112
|
||||
#define FR_SAFFIREPRO_CMD_AVC_MODEL_LARGE 0
|
||||
#define FR_SAFFIREPRO_CMD_AVC_MODEL_SMALL 1
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_PLL_LOCK_RANGE 113
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_EXIT_STANDALONE 114
|
||||
#define FR_SAFFIREPRO_CMD_EXIT_STANDALONE_CODE 0xA5A5
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_AVC_MODEL_MIDI 116
|
||||
#define FR_SAFFIREPRO_CMD_AVC_MODEL_MIDI_ON 1
|
||||
#define FR_SAFFIREPRO_CMD_AVC_MODEL_MIDI_OFF 0
|
||||
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIM_LEVEL 117
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_BITFIELD 118
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH1 0
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH2 1
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH3 2
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH4 3
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH5 4
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH6 5
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH7 6
|
||||
#define FR_SAFFIREPRO_CMD_ID_DIRECT_MONITORING_CH8 7
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Focusrite {
|
||||
|
||||
class SaffireProDevice;
|
||||
|
||||
// swiss army knife control class to serve
|
||||
// specific device control commands
|
||||
class SaffireProMultiControl
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
enum eMultiControlType {
|
||||
eTCT_Reboot,
|
||||
eTCT_FlashLed,
|
||||
eTCT_UseHighVoltageRail,
|
||||
eTCT_ExitStandalone,
|
||||
eTCT_PllLockRange,
|
||||
eTCT_SaveSettings,
|
||||
eTCT_EnableADAT1,
|
||||
eTCT_EnableADAT2,
|
||||
eTCT_EnableSPDIF,
|
||||
};
|
||||
|
||||
public:
|
||||
SaffireProMultiControl(SaffireProDevice& parent, enum eMultiControlType);
|
||||
SaffireProMultiControl(SaffireProDevice& parent, enum eMultiControlType,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(int v);
|
||||
virtual int getValue();
|
||||
virtual bool setValue(int idx, int v)
|
||||
{return setValue(v);};
|
||||
virtual int getValue(int idx)
|
||||
{return getValue();};
|
||||
|
||||
virtual int getMinimum() {return 0;};
|
||||
virtual int getMaximum() {return 0;};
|
||||
private:
|
||||
SaffireProDevice& m_Parent;
|
||||
enum eMultiControlType m_type;
|
||||
};
|
||||
|
||||
|
||||
class SaffireProMatrixMixer : public FocusriteMatrixMixer
|
||||
{
|
||||
public:
|
||||
enum eMatrixMixerType {
|
||||
eMMT_InputMix,
|
||||
eMMT_OutputMix
|
||||
};
|
||||
|
||||
public:
|
||||
SaffireProMatrixMixer(SaffireProDevice& parent, enum eMatrixMixerType type);
|
||||
SaffireProMatrixMixer(SaffireProDevice& parent, enum eMatrixMixerType type, std::string n);
|
||||
virtual ~SaffireProMatrixMixer() {};
|
||||
|
||||
virtual void show();
|
||||
|
||||
protected:
|
||||
void init();
|
||||
enum eMatrixMixerType m_type;
|
||||
};
|
||||
|
||||
// -- wrapper for the name stored on the device
|
||||
class SaffireProDeviceNameControl
|
||||
: public Control::Text
|
||||
{
|
||||
public:
|
||||
SaffireProDeviceNameControl(SaffireProDevice& parent);
|
||||
SaffireProDeviceNameControl(SaffireProDevice& parent,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool setValue(std::string);
|
||||
virtual std::string getValue();
|
||||
|
||||
private:
|
||||
SaffireProDevice& m_Parent;
|
||||
};
|
||||
|
||||
// -- wrapper for the standalone config of the device
|
||||
class SaffireProDeviceStandaloneEnum
|
||||
: public Control::Enum
|
||||
{
|
||||
public:
|
||||
SaffireProDeviceStandaloneEnum(SaffireProDevice& parent);
|
||||
SaffireProDeviceStandaloneEnum(SaffireProDevice& parent,
|
||||
std::string name, std::string label, std::string descr);
|
||||
|
||||
virtual bool select(int idx);
|
||||
virtual int selected();
|
||||
virtual int count();
|
||||
virtual std::string getEnumLabel(int idx);
|
||||
|
||||
private:
|
||||
SaffireProDevice& m_Parent;
|
||||
};
|
||||
|
||||
// -- the actual device
|
||||
class SaffireProDevice : public FocusriteDevice
|
||||
{
|
||||
|
||||
// we want all outside control to be done by this class
|
||||
friend class SaffireProMultiControl;
|
||||
friend class SaffireProDeviceNameControl;
|
||||
|
||||
public:
|
||||
SaffireProDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~SaffireProDevice();
|
||||
|
||||
virtual void showDevice();
|
||||
virtual void setVerboseLevel(int l);
|
||||
|
||||
virtual bool setSamplingFrequency( int );
|
||||
virtual int getSamplingFrequency( );
|
||||
virtual std::vector<int> getSupportedSamplingFrequencies();
|
||||
|
||||
virtual bool buildMixer();
|
||||
virtual bool destroyMixer();
|
||||
|
||||
virtual std::string getNickname();
|
||||
virtual bool setNickname(std::string name);
|
||||
virtual bool canChangeNickname();
|
||||
protected:
|
||||
void rebootDevice();
|
||||
void flashLed();
|
||||
bool isAudioOn();
|
||||
bool isMidiEnabled();
|
||||
bool isExtClockLocked();
|
||||
uint32_t getCount32();
|
||||
void exitStandalone();
|
||||
|
||||
void useHighVoltageRail(bool useIt);
|
||||
bool usingHighVoltageRail();
|
||||
unsigned int getPllLockRange();
|
||||
void setPllLockRange(unsigned int);
|
||||
void saveSettings();
|
||||
|
||||
bool setDeviceName(std::string n);
|
||||
std::string getDeviceName();
|
||||
|
||||
enum eDigitalChannel {
|
||||
eDC_ADAT1,
|
||||
eDC_ADAT2,
|
||||
eDC_SPDIF
|
||||
};
|
||||
|
||||
unsigned int getEnableDigitalChannel(enum eDigitalChannel);
|
||||
void setEnableDigitalChannel(enum eDigitalChannel, unsigned int);
|
||||
|
||||
bool isPro10()
|
||||
{return getConfigRom().getModelId() == 0x00000006;};
|
||||
bool isPro26()
|
||||
{return getConfigRom().getModelId() == 0x00000003;};
|
||||
|
||||
public:
|
||||
// override these since we want to use the focusrite way of setting
|
||||
// the clock
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
protected:
|
||||
virtual uint16_t getConfigurationIdSyncMode();
|
||||
virtual uint64_t getConfigurationId();
|
||||
|
||||
private:
|
||||
virtual bool setSamplingFrequencyDo( uint32_t );
|
||||
virtual bool setSamplingFrequencyDoNoReboot( uint32_t );
|
||||
|
||||
private:
|
||||
void updateClockSources();
|
||||
ClockSource m_internal_clocksource;
|
||||
ClockSource m_spdif_clocksource;
|
||||
ClockSource m_wordclock_clocksource;
|
||||
ClockSource m_adat1_clocksource;
|
||||
ClockSource m_adat2_clocksource;
|
||||
ClockSource *m_active_clocksource;
|
||||
|
||||
Control::Container *m_MixerContainer;
|
||||
Control::Container *m_ControlContainer;
|
||||
SaffireProDeviceNameControl *m_deviceNameControl;
|
||||
};
|
||||
|
||||
} // namespace Focusrite
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "onyxmixer.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Mackie {
|
||||
|
||||
OnyxMixerDevice::OnyxMixerDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d, configRom)
|
||||
{
|
||||
m_fixed_clocksource.type = FFADODevice::eCT_Internal;
|
||||
m_fixed_clocksource.valid = true;
|
||||
m_fixed_clocksource.locked = true;
|
||||
m_fixed_clocksource.id = 0;
|
||||
m_fixed_clocksource.slipping = false;
|
||||
m_fixed_clocksource.description = "Internal";
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Mackie::OnyxMixerDevice (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
}
|
||||
|
||||
OnyxMixerDevice::~OnyxMixerDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
OnyxMixerDevice::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::Mackie::OnyxMixerDevice\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
OnyxMixerDevice::getActiveClockSource() {
|
||||
return m_fixed_clocksource;
|
||||
}
|
||||
|
||||
bool
|
||||
OnyxMixerDevice::setActiveClockSource(ClockSource s) {
|
||||
// can't change, hence only succeed when identical
|
||||
return s.id == m_fixed_clocksource.id;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
OnyxMixerDevice::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_fixed_clocksource);
|
||||
return r;
|
||||
}
|
||||
|
||||
} // Mackie
|
||||
} // BeBoB
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_ONYX_MIXER_DEVICE_H
|
||||
#define BEBOB_ONYX_MIXER_DEVICE_H
|
||||
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Mackie {
|
||||
|
||||
class OnyxMixerDevice : public BeBoB::Device {
|
||||
|
||||
public:
|
||||
OnyxMixerDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~OnyxMixerDevice();
|
||||
|
||||
// override these since the mackie does not report
|
||||
// any the clock sources (it only supports internal clocking)
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
virtual void showDevice();
|
||||
private:
|
||||
ClockSource m_fixed_clocksource;
|
||||
};
|
||||
|
||||
} // namespace Mackie
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,259 @@
|
|||
<?xml version="1.0"?>
|
||||
<FFADOConnectionInfo>
|
||||
<Device>
|
||||
<NodeId>0</NodeId>
|
||||
<Comment>Connection Information for M-Audio, FW 410 configuration</Comment>
|
||||
<Vendor>M-Audio</Vendor>
|
||||
<Model>FW 410</Model>
|
||||
<GUID>0x000d6c0100698b96</GUID>
|
||||
|
||||
<ConnectionSet>
|
||||
<Direction>1</Direction>
|
||||
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>0</Plug>
|
||||
<Dimension>8</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>0</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>4</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut1 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut2 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>5</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut2 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>2</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut3 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>6</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut3 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>3</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut4 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>7</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut4 R</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>1</Plug>
|
||||
<Dimension>2</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>0</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFOut L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFOut R</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
|
||||
<!--
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>2</Plug>
|
||||
<Dimension>2</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>0</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>13</Format>
|
||||
<Type>10</Type>
|
||||
<DestinationPort>2</DestinationPort>
|
||||
<Name>MIDIOut L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>2</DestinationPort>
|
||||
<Name>Dummy</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
-->
|
||||
|
||||
</ConnectionSet>
|
||||
|
||||
|
||||
<ConnectionSet>
|
||||
<Direction>0</Direction>
|
||||
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>0</Plug>
|
||||
<Dimension>2</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>1</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineIn1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineIn1 R</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
|
||||
<!--
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>1</Plug>
|
||||
<Dimension>2</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>0</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFIn1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFIn1 R</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
-->
|
||||
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>2</Plug>
|
||||
<Dimension>2</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>0</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>13</Format>
|
||||
<Type>10</Type>
|
||||
<DestinationPort>2</DestinationPort>
|
||||
<Name>MIDIIn</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>2</DestinationPort>
|
||||
<Name>Dummy</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
|
||||
</ConnectionSet>
|
||||
|
||||
|
||||
<StreamFormats>
|
||||
<Direction>1</Direction>
|
||||
<Format>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<AudioChannels>10</AudioChannels>
|
||||
<MidiChannels>0</MidiChannels>
|
||||
</Format>
|
||||
</StreamFormats>
|
||||
<StreamFormats>
|
||||
<Direction>0</Direction>
|
||||
<Format>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<AudioChannels>2</AudioChannels>
|
||||
<MidiChannels>2</MidiChannels>
|
||||
</Format>
|
||||
</StreamFormats>
|
||||
</Device>
|
||||
</FFADOConnectionInfo>
|
|
@ -0,0 +1,157 @@
|
|||
<?xml version="1.0"?>
|
||||
<FFADOConnectionInfo>
|
||||
<Device>
|
||||
<NodeId>0</NodeId>
|
||||
<Comment>Connection Information for M-Audio, FW Audiophile configuration</Comment>
|
||||
<Vendor>M-Audio</Vendor>
|
||||
<Model>FW Audiophile</Model>
|
||||
<GUID>0x000D6C031088FA68</GUID>
|
||||
|
||||
<ConnectionSet>
|
||||
<Direction>1</Direction>
|
||||
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>0</Plug>
|
||||
<Dimension>7</Dimension>
|
||||
<Samplerate>44100</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>0</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>2</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>4</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut1 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>3</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut2 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>5</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut2 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFOut L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFOut R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>6</Position>
|
||||
<Location>0</Location>
|
||||
<Format>13</Format>
|
||||
<Type>10</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>MidiPort</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
</ConnectionSet>
|
||||
|
||||
<ConnectionSet>
|
||||
<Direction>0</Direction>
|
||||
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Plug>0</Plug>
|
||||
<Dimension>5</Dimension>
|
||||
<Samplerate>44100</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Master>1</Master>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFIn1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>1</DestinationPort>
|
||||
<Name>SPDIFIn1 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>2</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineIn1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>3</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineIn1 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>4</Position>
|
||||
<Location>0</Location>
|
||||
<Format>13</Format>
|
||||
<Type>10</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>MidiPort</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
|
||||
</ConnectionSet>
|
||||
|
||||
|
||||
<StreamFormats>
|
||||
<Direction>1</Direction>
|
||||
<Format>
|
||||
<Samplerate>44100</Samplerate>
|
||||
<AudioChannels>6</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
</StreamFormats>
|
||||
<StreamFormats>
|
||||
<Direction>0</Direction>
|
||||
<Format>
|
||||
<Samplerate>44100</Samplerate>
|
||||
<AudioChannels>4</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
</StreamFormats>
|
||||
</Device>
|
||||
</FFADOConnectionInfo>
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "normal_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace MAudio {
|
||||
namespace Normal {
|
||||
|
||||
Device::Device(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ),
|
||||
unsigned int modelId)
|
||||
: BeBoB::Device( d, configRom)
|
||||
{
|
||||
switch ( modelId ) {
|
||||
case 0x00010046: // fw410
|
||||
m_id = FW_410;
|
||||
break;
|
||||
case 0x00010060: // Audiophile
|
||||
m_id = FW_AUDIOPHILE;
|
||||
break;
|
||||
case 0x00010062: // Solo
|
||||
m_id = FW_SOLO;
|
||||
break;
|
||||
case 0x0000000a:
|
||||
m_id = FW_OZONIC;
|
||||
break;
|
||||
}
|
||||
updateClkSrc();
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::MAudio::Normal::Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::MAudio::Normal::Device\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
bool Device::updateClkSrc()
|
||||
{
|
||||
int plugid;
|
||||
|
||||
m_internal_clksrc.type = FFADODevice::eCT_Internal;
|
||||
m_internal_clksrc.active = false;
|
||||
m_internal_clksrc.valid = true;
|
||||
m_internal_clksrc.locked = true;
|
||||
m_internal_clksrc.id = 0x01;
|
||||
m_internal_clksrc.slipping = false;
|
||||
m_internal_clksrc.description = "Internal";
|
||||
|
||||
m_spdif_clksrc.type = FFADODevice::eCT_SPDIF;
|
||||
m_spdif_clksrc.active = false;
|
||||
m_spdif_clksrc.valid = false;
|
||||
m_spdif_clksrc.locked = false;
|
||||
m_spdif_clksrc.id = 0;
|
||||
m_spdif_clksrc.slipping = false;
|
||||
m_spdif_clksrc.description = "S/PDIF (Coaxial)";
|
||||
|
||||
m_adat_clksrc.type = FFADODevice::eCT_ADAT;
|
||||
m_adat_clksrc.active = false;
|
||||
m_adat_clksrc.valid = false;
|
||||
m_adat_clksrc.locked = false;
|
||||
m_adat_clksrc.id = 0;
|
||||
m_adat_clksrc.slipping = false;
|
||||
m_adat_clksrc.description = "ADAT (Optical)";
|
||||
|
||||
switch (m_id) {
|
||||
case FW_410: // fw410
|
||||
m_spdif_clksrc.active = true;
|
||||
m_spdif_clksrc.valid = true;
|
||||
m_spdif_clksrc.id = 0x82;
|
||||
m_adat_clksrc.active = true;
|
||||
m_adat_clksrc.valid = true;
|
||||
m_adat_clksrc.id = 0x83;
|
||||
break;
|
||||
case FW_AUDIOPHILE: // Audiophile
|
||||
m_spdif_clksrc.active = true;
|
||||
m_spdif_clksrc.valid = true;
|
||||
m_spdif_clksrc.id = 0x82;
|
||||
break;
|
||||
case FW_SOLO: // Solo
|
||||
m_spdif_clksrc.active = true;
|
||||
m_spdif_clksrc.valid = true;
|
||||
m_spdif_clksrc.id = 0x81;
|
||||
break;
|
||||
case FW_OZONIC:
|
||||
/* internal only */
|
||||
m_active_clksrc = &m_internal_clksrc;
|
||||
return true;
|
||||
}
|
||||
|
||||
plugid = getClkSrc();
|
||||
if (plugid < 0)
|
||||
return false;
|
||||
|
||||
if (plugid == 0x01) {
|
||||
m_internal_clksrc.active = true;
|
||||
m_active_clksrc = &m_internal_clksrc;
|
||||
} else if (plugid == 0x83) {
|
||||
m_adat_clksrc.active = true;
|
||||
m_active_clksrc = &m_adat_clksrc;
|
||||
} else {
|
||||
m_spdif_clksrc.active = true;
|
||||
m_active_clksrc = &m_spdif_clksrc;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Device::getClkSrc()
|
||||
{
|
||||
AVC::SignalSourceCmd cmd( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Status );
|
||||
cmd.setNodeId( getNodeId() );
|
||||
cmd.setSubunitType( AVC::eST_Unit );
|
||||
cmd.setSubunitId( 0xff );
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
|
||||
AVC::SignalSubunitAddress dst;
|
||||
dst.m_subunitType = AVC::eST_Music;
|
||||
dst.m_subunitId = 0x00;
|
||||
dst.m_plugId = 0x01;
|
||||
cmd.setSignalDestination( dst );
|
||||
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "Signal source command failed\n" );
|
||||
return -1;
|
||||
}
|
||||
AVC::SignalAddress* pSyncPlugSignalAddress = cmd.getSignalSource();
|
||||
|
||||
AVC::SignalSubunitAddress* pSyncPlugSubunitAddress
|
||||
= dynamic_cast<AVC::SignalSubunitAddress*>( pSyncPlugSignalAddress );
|
||||
if ( pSyncPlugSubunitAddress ) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
|
||||
( pSyncPlugSubunitAddress->m_subunitType << 3
|
||||
| pSyncPlugSubunitAddress->m_subunitId ) << 8
|
||||
| pSyncPlugSubunitAddress->m_plugId );
|
||||
return pSyncPlugSubunitAddress->m_plugId;
|
||||
}
|
||||
|
||||
AVC::SignalUnitAddress* pSyncPlugUnitAddress
|
||||
= dynamic_cast<AVC::SignalUnitAddress*>( pSyncPlugSignalAddress );
|
||||
if ( pSyncPlugUnitAddress ) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
|
||||
0xff << 8 | pSyncPlugUnitAddress->m_plugId );
|
||||
return pSyncPlugUnitAddress->m_plugId;
|
||||
}
|
||||
|
||||
debugError( "Could not retrieve sync mode\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
Device::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
|
||||
r.push_back(m_internal_clksrc);
|
||||
|
||||
if (m_spdif_clksrc.active)
|
||||
r.push_back(m_spdif_clksrc);
|
||||
|
||||
if (m_adat_clksrc.active)
|
||||
r.push_back(m_adat_clksrc);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
Device::getActiveClockSource()
|
||||
{
|
||||
if (!updateClkSrc()) {
|
||||
ClockSource s;
|
||||
s.type = eCT_Invalid;
|
||||
return s;
|
||||
}
|
||||
return *m_active_clksrc;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setActiveClockSource(ClockSource s)
|
||||
{
|
||||
AVC::SignalSourceCmd cmd( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Control );
|
||||
cmd.setNodeId( getNodeId() );
|
||||
cmd.setSubunitType( AVC::eST_Unit );
|
||||
cmd.setSubunitId( 0xff );
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
|
||||
AVC::SignalSubunitAddress dst;
|
||||
dst.m_subunitType = AVC::eST_Music;
|
||||
dst.m_subunitId = 0x00;
|
||||
dst.m_plugId = 0x01;
|
||||
cmd.setSignalDestination( dst );
|
||||
|
||||
if (s.id == 0x01) {
|
||||
AVC::SignalSubunitAddress src;
|
||||
src.m_subunitType = AVC::eST_Music;
|
||||
src.m_subunitId = 0x00;
|
||||
src.m_plugId = 0x01;
|
||||
cmd.setSignalSource( src );
|
||||
} else {
|
||||
AVC::SignalUnitAddress src;
|
||||
src.m_plugId = s.id;
|
||||
cmd.setSignalSource( src );
|
||||
}
|
||||
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "Signal source command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Normal
|
||||
} // namespace MAudio
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_MAUDIO_NORMAL_DEVICE_H
|
||||
#define BEBOB_MAUDIO_NORMAL_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace MAudio {
|
||||
namespace Normal {
|
||||
|
||||
enum DeviceID {
|
||||
FW_410,
|
||||
FW_AUDIOPHILE,
|
||||
FW_SOLO,
|
||||
FW_OZONIC
|
||||
};
|
||||
|
||||
class Device : public BeBoB::Device {
|
||||
public:
|
||||
Device( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ),
|
||||
unsigned int modelId);
|
||||
virtual ~Device();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
private:
|
||||
bool updateClkSrc();
|
||||
int getClkSrc();
|
||||
ClockSource m_internal_clksrc;
|
||||
ClockSource m_spdif_clksrc;
|
||||
ClockSource m_adat_clksrc;
|
||||
ClockSource *m_active_clksrc;
|
||||
enum DeviceID m_id;
|
||||
};
|
||||
|
||||
} // namespace Normal
|
||||
} // namespace MAudio
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,192 @@
|
|||
<?xml version="1.0"?>
|
||||
<FFADOConnectionInfo>
|
||||
<Device>
|
||||
<NodeId>1</NodeId>
|
||||
<Comment>Connection Information for bridgeCo AG, Switzerland , Ref-Design_Audio1 configuration</Comment>
|
||||
<Vendor>bridgeCo AG, Switzerland </Vendor>
|
||||
<Model>Ref-Design_Audio1</Model>
|
||||
<GUID>0007f51000000042</GUID>
|
||||
<ConnectionSet>
|
||||
<Direction>1</Direction>
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Dimension>9</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>4</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut1 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut2 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>5</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut2 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>2</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut3 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>6</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineOut3 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>3</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>SPDIFOut L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>7</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>SPDIFOut R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>8</Position>
|
||||
<Location>9</Location>
|
||||
<Format>13</Format>
|
||||
<Type>10</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>MidiOut 1</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
</ConnectionSet>
|
||||
<ConnectionSet>
|
||||
<Direction>0</Direction>
|
||||
<Connection>
|
||||
<Port>0</Port>
|
||||
<Node>1</Node>
|
||||
<Dimension>5</Dimension>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<IsoChannel>-1</IsoChannel>
|
||||
<Streams>
|
||||
<Stream>
|
||||
<Position>1</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineIn1 L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>3</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>3</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>LineIn1 R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>0</Position>
|
||||
<Location>1</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>SPDIFIn L</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>2</Position>
|
||||
<Location>2</Location>
|
||||
<Format>6</Format>
|
||||
<Type>4</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>SPDIFIn R</Name>
|
||||
</Stream>
|
||||
<Stream>
|
||||
<Position>4</Position>
|
||||
<Location>5</Location>
|
||||
<Format>13</Format>
|
||||
<Type>10</Type>
|
||||
<DestinationPort>0</DestinationPort>
|
||||
<Name>MidiIn 1</Name>
|
||||
</Stream>
|
||||
</Streams>
|
||||
</Connection>
|
||||
</ConnectionSet>
|
||||
<StreamFormats>
|
||||
<Direction>1</Direction>
|
||||
<Format>
|
||||
<Samplerate>44100</Samplerate>
|
||||
<AudioChannels>8</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
<Format>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<AudioChannels>8</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
<Format>
|
||||
<Samplerate>88200</Samplerate>
|
||||
<AudioChannels>8</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
<Format>
|
||||
<Samplerate>96000</Samplerate>
|
||||
<AudioChannels>8</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
</StreamFormats>
|
||||
<StreamFormats>
|
||||
<Direction>0</Direction>
|
||||
<Format>
|
||||
<Samplerate>44100</Samplerate>
|
||||
<AudioChannels>4</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
<Format>
|
||||
<Samplerate>48000</Samplerate>
|
||||
<AudioChannels>4</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
<Format>
|
||||
<Samplerate>88200</Samplerate>
|
||||
<AudioChannels>4</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
<Format>
|
||||
<Samplerate>96000</Samplerate>
|
||||
<AudioChannels>4</AudioChannels>
|
||||
<MidiChannels>1</MidiChannels>
|
||||
</Format>
|
||||
</StreamFormats>
|
||||
</Device>
|
||||
</FFADOConnectionInfo>
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "libutil/Configuration.h"
|
||||
#include "libutil/ByteSwap.h"
|
||||
#include "libutil/SystemTimeSource.h"
|
||||
|
||||
#include <libraw1394/csr.h>
|
||||
#include <libieee1394/IEC61883.h>
|
||||
|
||||
#include "bebob/maudio/special_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace MAudio {
|
||||
namespace Special {
|
||||
|
||||
Device::Device(DeviceManager& d, ffado_smartptr<ConfigRom>(configRom))
|
||||
: BeBoB::Device(d, configRom)
|
||||
{
|
||||
is1814 = (getConfigRom().getModelId() == 0x00010071);
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Created BeBoB::MAudio::Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId());
|
||||
updateClockSources();
|
||||
}
|
||||
|
||||
void Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::MAudio::Device\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Discoveing plugs:
|
||||
* The firmware can't respond any commands related to plug info.
|
||||
*/
|
||||
bool Device::discover()
|
||||
{
|
||||
/* keep track of the config id of this discovery */
|
||||
m_last_discovery_config_id = getConfigurationId();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* don't lock to prevent from streaming */
|
||||
bool Device::lock()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Device::Unlock()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* don't cache */
|
||||
bool Device::loadFromCache()
|
||||
{
|
||||
return buildMixer();
|
||||
}
|
||||
bool Device::saveCache()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Device::buildMixer()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Building a maudio special mixer...\n");
|
||||
|
||||
delete m_special_mixer;
|
||||
|
||||
m_special_mixer = new Mixer(*this);
|
||||
if (m_special_mixer)
|
||||
m_special_mixer->setVerboseLevel(getDebugLevel());
|
||||
|
||||
return (m_special_mixer != NULL);
|
||||
}
|
||||
|
||||
bool Device::destroyMixer()
|
||||
{
|
||||
delete m_special_mixer;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sampling frequency support:
|
||||
* set: Input/Output Signal Format command
|
||||
* get: Input Signal Format command (or metering information)
|
||||
*
|
||||
* TODO
|
||||
*/
|
||||
std::vector<int> Device::getSupportedSamplingFrequencies()
|
||||
{
|
||||
std::vector<int> freqs;
|
||||
freqs.push_back(0);
|
||||
return freqs;
|
||||
}
|
||||
bool Device::supportsSamplingFrequency(int s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
int Device::getSamplingFrequency()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clock Source support:
|
||||
* TODO: use ALSA control interface
|
||||
*
|
||||
*/
|
||||
void Device::updateClockSources()
|
||||
{
|
||||
m_fixed_clksrc.type = FFADODevice::eCT_Internal;
|
||||
m_fixed_clksrc.active = true;
|
||||
m_fixed_clksrc.valid = true;
|
||||
m_fixed_clksrc.locked = true;
|
||||
m_fixed_clksrc.id = 0;
|
||||
m_fixed_clksrc.slipping = false;
|
||||
m_fixed_clksrc.description = "Controlled by ALSA";
|
||||
}
|
||||
FFADODevice::ClockSourceVector
|
||||
Device::getSupportedClockSources()
|
||||
{
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_fixed_clksrc);
|
||||
return r;
|
||||
}
|
||||
FFADODevice::ClockSource
|
||||
Device::getActiveClockSource()
|
||||
{
|
||||
return m_fixed_clksrc;
|
||||
}
|
||||
bool
|
||||
Device::setActiveClockSource(ClockSource s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Streaming State:
|
||||
* The firmware can't respond against frequent requests.
|
||||
* TODO: how to void frequent transaction?
|
||||
*/
|
||||
enum FFADODevice::eStreamingState
|
||||
Device::getStreamingState()
|
||||
{
|
||||
return eSS_Both;
|
||||
}
|
||||
|
||||
/*
|
||||
* The firmware can't speak:
|
||||
* 'Extended Plug Info command' (BridgeCo)
|
||||
* 'Connection and Compatibility Management' (1394TA)
|
||||
*/
|
||||
uint8_t
|
||||
Device::getConfigurationIdSampleRate()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
uint8_t
|
||||
Device::getConfigurationIdNumberOfChannel( AVC::PlugAddress::EPlugDirection ePlugDirection )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
uint16_t
|
||||
Device::getConfigurationIdSyncMode()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool Device::readReg(uint64_t offset, uint32_t *data)
|
||||
{
|
||||
Util::MutexLockHelper lock(m_DeviceMutex);
|
||||
|
||||
/* read cache because it's 'write-only' */
|
||||
*data = m_regs[offset / 4];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Device::writeReg(uint64_t offset, uint32_t data)
|
||||
{
|
||||
int trials;
|
||||
fb_nodeid_t nodeId;
|
||||
fb_nodeaddr_t addr;
|
||||
fb_quadlet_t quad;
|
||||
|
||||
Util::MutexLockHelper lock(m_DeviceMutex);
|
||||
|
||||
nodeId = getNodeId() | 0xffc0;
|
||||
addr = MAUDIO_SPECIFIC_ADDRESS + MAUDIO_CONTROL_OFFSET + offset;
|
||||
quad = CondSwapToBus32(data);
|
||||
|
||||
/* cache because it's 'write-only' */
|
||||
m_regs[offset / 4] = data;
|
||||
|
||||
trials = 0;
|
||||
do {
|
||||
if (get1394Service().write_quadlet(nodeId, addr, quad))
|
||||
break;
|
||||
Util::SystemTimeSource::SleepUsecRelative(100);
|
||||
} while (++trials < 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Device::writeBlk(uint64_t offset, unsigned int size, uint32_t *data)
|
||||
{
|
||||
fb_nodeid_t nodeId;
|
||||
fb_nodeaddr_t addr;
|
||||
unsigned int i, length, trials;
|
||||
|
||||
nodeId = getNodeId() | 0xffc0;
|
||||
addr = MAUDIO_SPECIFIC_ADDRESS + MAUDIO_CONTROL_OFFSET + offset;
|
||||
length = size /4;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
/* the device applies the setting even if the device don't respond */
|
||||
m_regs[i] = data[i];
|
||||
data[i] = CondSwapToBus32(data[i]);
|
||||
}
|
||||
|
||||
trials = 0;
|
||||
do {
|
||||
if (get1394Service().write(nodeId, addr, length, (fb_quadlet_t*)data))
|
||||
break;
|
||||
Util::SystemTimeSource::SleepUsecRelative(100);
|
||||
} while (++trials < 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Special
|
||||
} // namespace MAudio
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_MAUDIO_SPECIAL_DEVICE_H
|
||||
#define BEBOB_MAUDIO_SPECIAL_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
#include "bebob/maudio/special_mixer.h"
|
||||
|
||||
/*
|
||||
* FireWire 1814 and ProjectMix I/O uses special firmware. It will be freezed
|
||||
* if receiving any commands which the firmware can't understand. These devices
|
||||
* utilize completely different system to control. It is read/write transaction
|
||||
* directly into a certain address.
|
||||
*/
|
||||
#define MAUDIO_SPECIFIC_ADDRESS 0xffc700000000
|
||||
|
||||
/*
|
||||
* FW1814/ProjectMix don't use AVC for control. The driver cannot refer to
|
||||
* current parameters by asynchronous transaction. The driver is allowed to
|
||||
* write transaction so MUST remember the current values.
|
||||
*/
|
||||
#define MAUDIO_CONTROL_OFFSET 0x00700000
|
||||
|
||||
/*
|
||||
* GAIN for inputs:
|
||||
* Write 32bit. upper 16bit for left chennal and lower 16bit for right.
|
||||
* The value is between 0x8000(low) to 0x0000(high) as the same as '10.3.1
|
||||
* Volume Control' in 'AV/C Audio Subunit Specification 1.0 (1394TA 1999008)'.
|
||||
*/
|
||||
#define GAIN_STM_12_IN 0x00
|
||||
#define GAIN_STM_34_IN 0x04
|
||||
#define GAIN_ANA_12_OUT 0x08
|
||||
#define GAIN_ANA_34_OUT 0x0c
|
||||
#define GAIN_ANA_12_IN 0x10
|
||||
#define GAIN_ANA_34_IN 0x14
|
||||
#define GAIN_ANA_56_IN 0x18
|
||||
#define GAIN_ANA_78_IN 0x1c
|
||||
#define GAIN_SPDIF_12_IN 0x20
|
||||
#define GAIN_ADAT_12_IN 0x24
|
||||
#define GAIN_ADAT_34_IN 0x28
|
||||
#define GAIN_ADAT_56_IN 0x2c
|
||||
#define GAIN_ADAT_78_IN 0x30
|
||||
#define GAIN_AUX_12_OUT 0x34
|
||||
#define GAIN_HP_12_OUT 0x38
|
||||
#define GAIN_HP_34_OUT 0x3c
|
||||
/*
|
||||
* LR balance:
|
||||
* Write 32 bit, upper 16bit for left channel and lower 16bit for right.
|
||||
* The value is between 0x800(L) to 0x7FFE(R) as the same as '10.3.3 LR Balance
|
||||
* Control' in 'AV/C Audio Subunit Specification 1.0 (1394TA 1999008)'.
|
||||
*/
|
||||
#define LR_ANA_12_IN 0x40
|
||||
#define LR_ANA_34_IN 0x44
|
||||
#define LR_ANA_56_IN 0x48
|
||||
#define LR_ANA_78_IN 0x4c
|
||||
#define LR_SPDIF_12_IN 0x50
|
||||
#define LR_ADAT_12_IN 0x54
|
||||
#define LR_ADAT_34_IN 0x58
|
||||
#define LR_ADAT_56_IN 0x5c
|
||||
#define LR_ADAT_78_IN 0x60
|
||||
/*
|
||||
* AUX inputs:
|
||||
* This is the same as 'gain' control above.
|
||||
*/
|
||||
#define AUX_STM_12_IN 0x64
|
||||
#define AUX_STM_34_IN 0x68
|
||||
#define AUX_ANA_12_IN 0x6c
|
||||
#define AUX_ANA_34_IN 0x70
|
||||
#define AUX_ANA_56_IN 0x74
|
||||
#define AUX_ANA_78_IN 0x78
|
||||
#define AUX_SPDIF_12_IN 0x7c
|
||||
#define AUX_ADAT_12_IN 0x80
|
||||
#define AUX_ADAT_34_IN 0x84
|
||||
#define AUX_ADAT_56_IN 0x88
|
||||
#define AUX_ADAT_78_IN 0x8c
|
||||
/*
|
||||
* MIXER inputs:
|
||||
* There are bit flags. If flag is 0x01, it means on.
|
||||
*
|
||||
* MIX_ANA_DIG_IN:
|
||||
* Write 32bits, upper 16bit for digital inputs and lowe 16bit for analog inputs.
|
||||
* Digital inputs:
|
||||
* Lower 2bits are used. upper for 'to Mix3/4' and lower for 'to Mix1/2'.
|
||||
* Analog inputs:
|
||||
* Lower 8bits are used. upper 4bits for 'to Mix3/4' and lower for 'to
|
||||
* Mix1/2'. Inner the 4bit, for 'from Ana7/8', for 'from Ana5/6', for 'from
|
||||
* Ana3/4', for 'from Ana1/2'.
|
||||
*
|
||||
* MIX_STM_IN:
|
||||
* Write 32bits, lower 4bits are used. upper 2bits for 'from Stm1/2' and lower
|
||||
* for 'from Stm3/4'. Inner the 2bits, for 'to Mix3/4' and for 'to
|
||||
* Mix1/2'.
|
||||
*/
|
||||
#define MIX_ANA_DIG_IN 0x90
|
||||
#define MIX_STM_IN 0x94
|
||||
/*
|
||||
* SRC for output:
|
||||
* Write 32bit. There are bit flags. If the flag is 0x01, it means on.
|
||||
*
|
||||
* SRC_HP_OUT:
|
||||
* Lower 3bits are used, 'from Aux12', 'from Mix34', 'from
|
||||
* Mix12'.
|
||||
*
|
||||
* SRC_ANA_OUT:
|
||||
* Lower 2 bits are used, 'to Ana34', 'to Ana12'. If bit is 0x01, it
|
||||
* means 'from Aux12' else 'From Mix12 (or Mix34)'.
|
||||
*/
|
||||
#define SRC_HP_OUT 0x98
|
||||
#define SRC_ANA_OUT 0x9c
|
||||
|
||||
namespace BeBoB {
|
||||
namespace MAudio {
|
||||
namespace Special {
|
||||
|
||||
class Device : public BeBoB::Device
|
||||
{
|
||||
public:
|
||||
Device(DeviceManager& d, ffado_smartptr<ConfigRom>(configRom));
|
||||
virtual ~Device() {};
|
||||
virtual void showDevice();
|
||||
|
||||
bool lock();
|
||||
bool Unlock();
|
||||
bool loadFromCache();
|
||||
bool saveCache();
|
||||
|
||||
virtual bool discover();
|
||||
virtual bool buildMixer();
|
||||
virtual bool destroyMixer();
|
||||
|
||||
std::vector<int> getSupportedSamplingFrequencies();
|
||||
bool supportsSamplingFrequency( int s ); int getSamplingFrequency();
|
||||
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
virtual enum FFADODevice::eStreamingState getStreamingState();
|
||||
|
||||
virtual bool readReg(uint64_t addr, uint32_t *data);
|
||||
virtual bool writeReg(uint64_t addr, uint32_t data);
|
||||
bool writeBlk(uint64_t offset, unsigned int length, uint32_t *data);
|
||||
protected:
|
||||
virtual uint8_t getConfigurationIdSampleRate();
|
||||
virtual uint8_t getConfigurationIdNumberOfChannel(AVC::PlugAddress::EPlugDirection ePlugDirection);
|
||||
virtual uint16_t getConfigurationIdSyncMode();
|
||||
|
||||
private:
|
||||
void updateClockSources();
|
||||
ClockSource m_fixed_clksrc;
|
||||
|
||||
Mixer *m_special_mixer;
|
||||
bool is1814;
|
||||
|
||||
/* cache for mixer settings */
|
||||
uint32_t m_regs[(0x9c + 4) / 4];
|
||||
};
|
||||
|
||||
} // namespace Special
|
||||
} // namespace MAudio
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif /* BEBOB_MAUDIO_SPECIAL_DEVICE_H */
|
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
#include "libieee1394/configrom.h"
|
||||
|
||||
#include "libcontrol/BasicElements.h"
|
||||
#include "libutil/ByteSwap.h"
|
||||
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
#include "bebob/bebob_avdevice_subunit.h"
|
||||
|
||||
#include "bebob/maudio/special_mixer.h"
|
||||
#include "bebob/maudio/special_avdevice.h"
|
||||
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
namespace MAudio {
|
||||
namespace Special {
|
||||
|
||||
class Device;
|
||||
|
||||
IMPL_DEBUG_MODULE(Mixer, Mixer, DEBUG_LEVEL_NORMAL);
|
||||
|
||||
Mixer::Mixer(Device &dev)
|
||||
: Control::Container((Device *)&dev)
|
||||
, m_dev((Device *) &dev)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < 28; i++)
|
||||
addElement(new Volume(dev, i));
|
||||
for (i = 1; i < 10; i++)
|
||||
addElement(new LRBalance(dev, i));
|
||||
for (i = 1; i < 5; i++)
|
||||
addElement(new Selector(dev, i));
|
||||
for (i = 1; i < 3; i++)
|
||||
addElement(new Processing(dev, i));
|
||||
|
||||
if (!initialize(dev))
|
||||
debugWarning("Could not initialize mixer settings\n");
|
||||
|
||||
if (!((Device *) &dev)->addElement(this))
|
||||
debugWarning("Could not add BeBoB::MAudio::Special::Mixer to Control::Container\n");
|
||||
}
|
||||
|
||||
bool Mixer::initialize(Device &dev)
|
||||
{
|
||||
uint32_t *data;
|
||||
unsigned int i;
|
||||
bool err;
|
||||
|
||||
data = (uint32_t *)malloc(0x9c + 4);
|
||||
if (data == NULL)
|
||||
return false;
|
||||
|
||||
/* inputs volumes */
|
||||
for (i = 0; i < 16; i++)
|
||||
data[i] = 0x00000000;
|
||||
/* inputs panning */
|
||||
for (i = 16; i < 25; i++)
|
||||
data[i] = 0x7ffe8000;
|
||||
/* aux inputs volume */
|
||||
for (i = 25; i < 36; i++)
|
||||
data[i] = 0x00000000;
|
||||
/* analog inputs to mixer */
|
||||
data[36] = 0x00000000;
|
||||
/* stream inputs to mixer */
|
||||
data[37] = 0x00000000;
|
||||
/* headphone sources */
|
||||
data[38] = 0x00000000;
|
||||
/* output sources */
|
||||
data[39] = 0x00000000;
|
||||
|
||||
err = dev.writeBlk(0x00, 0x9c + 4, data);
|
||||
free(data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Output source control:
|
||||
* Path Target Offset
|
||||
* /Mixer/Selector_1 HP 1/2 out 0x98
|
||||
* /Mixer/Selector_2 HP 3/4 out 0x98
|
||||
* /Mixer/Selector_3 Analog 1/2 out 0x9C
|
||||
* /Mixer/Selector_4 Analog 3/4 out 0x9C
|
||||
* There seems not to be for digital output.
|
||||
*/
|
||||
Selector::Selector(Device& dev, unsigned int id)
|
||||
: Control::Discrete((Device *)&dev)
|
||||
, m_dev(&dev)
|
||||
, m_id(id)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << "Selector_" << id;
|
||||
Control::Discrete::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for Selector " << id;
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for Selector " << id;
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
uint64_t Selector::getOffset()
|
||||
{
|
||||
if (m_id < 3)
|
||||
return 0x98;
|
||||
else
|
||||
return 0x9c;
|
||||
}
|
||||
|
||||
bool Selector::setValue(int id, int v)
|
||||
{
|
||||
uint32_t data, value;
|
||||
|
||||
if (!m_dev->readReg(getOffset(), &data))
|
||||
return false;
|
||||
|
||||
/* for headphone out */
|
||||
if (m_id < 3) {
|
||||
if (v == 2)
|
||||
value = 0x04;
|
||||
else if (v == 1)
|
||||
value = 0x02;
|
||||
else
|
||||
value = 0x01;
|
||||
|
||||
if (m_id == 1)
|
||||
data = (data & 0xffff0000) | value;
|
||||
else
|
||||
data = (value << 16) | (data & 0xffff);
|
||||
} else {
|
||||
value = 0x01 & v;
|
||||
if (m_id == 3)
|
||||
data = (data & 0x02) | value;
|
||||
else
|
||||
data = (value << 1) | (data & 0x01);
|
||||
}
|
||||
|
||||
return m_dev->writeReg(getOffset(), data);
|
||||
}
|
||||
|
||||
int Selector::getValue(int id)
|
||||
{
|
||||
uint32_t data, value;
|
||||
|
||||
if (!m_dev->readReg(getOffset(), &data))
|
||||
return 0;
|
||||
|
||||
if (m_id < 3) {
|
||||
if (m_id == 1)
|
||||
data = data & 0xffff;
|
||||
else
|
||||
data = data >> 16;
|
||||
|
||||
if (data & 0x04)
|
||||
value = 2;
|
||||
else if (data & 0x02)
|
||||
value = 1;
|
||||
else
|
||||
value = 0;
|
||||
} else if (m_id == 3)
|
||||
value = 0x01 & data;
|
||||
else
|
||||
value = (0x02 & data) >> 1;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input volume control:
|
||||
* Path Target Offset
|
||||
* /Mixer/Feature_Volume_1 Analog 1/2 in 0x10
|
||||
* /Mixer/Feature_Volume_2 Analog 3/4 in 0x14
|
||||
* /Mixer/Feature_Volume_3 Analog 5/6 in 0x18
|
||||
* /Mixer/Feature_Volume_4 Analog 7/8 in 0x1c
|
||||
* /Mixer/Feature_Volume_5 SPDIF 1/2 in 0x20
|
||||
* /Mixer/Feature_Volume_6 ADAT 1/2 in 0x24
|
||||
* /Mixer/Feature_Volume_7 ADAT 3/4 in 0x28
|
||||
* /Mixer/Feature_Volume_8 ADAT 5/6 in 0x2c
|
||||
* /Mixer/Feature_Volume_9 ADAT 7/8 in 0x30
|
||||
* /Mixer/Feature_Volume_10 Stream 1/2 in 0x00
|
||||
* /Mixer/Feature_Volume_11 Stream 3/4 in 0x04
|
||||
*
|
||||
* Output volume control:
|
||||
* /Mixer/Feature_Volume_12 Analog 1/2 out 0x08
|
||||
* /Mixer/Feature_Volume_13 Analog 3/4 out 0x0c
|
||||
* /Mixer/Feature_Volume_14 AUX 1/2 out 0x34
|
||||
* /Mixer/Feature_Volume_15 HP 1/2 out 0x38
|
||||
* /Mixer/Feature_Volume_16 HP 3/4 out 0x3c
|
||||
*
|
||||
* Aux input control:
|
||||
* Path Target Offset
|
||||
* /Mixer/Feature_Volume_17 Stream 1/2 in 0x64
|
||||
* /Mixer/Feature_Volume_18 Stream 3/4 in 0x68
|
||||
* /Mixer/Feature_Volume_19 Analog 1/2 in 0x6c
|
||||
* /Mixer/Feature_Volume_20 Analog 3/4 in 0x70
|
||||
* /Mixer/Feature_Volume_21 Analog 5/6 in 0x74
|
||||
* /Mixer/Feature_Volume_22 Analog 7/8 in 0x78
|
||||
* /Mixer/Feature_Volume_23 S/PDIF 1/2 in 0x7c
|
||||
* /Mixer/Feature_Volume_24 ADAT 1/2 in 0x80
|
||||
* /Mixer/Feature_Volume_25 ADAT 3/4 in 0x84
|
||||
* /Mixer/Feature_Volume_26 ADAT 5/6 in 0x88
|
||||
* /Mixer/Feature_Volume_27 ADAT 7/8 in 0x8c
|
||||
*/
|
||||
Volume::Volume(Device &dev, unsigned int id)
|
||||
: Control::Continuous((Device *)&dev)
|
||||
, m_dev(&dev)
|
||||
, m_id(id)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << "Feature_Volume_" << id;
|
||||
Control::Continuous::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for Feature Volume" << id;
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for Feature Volume " << id;
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
uint64_t Volume::getOffset()
|
||||
{
|
||||
if ((m_id > 0) && (m_id < 10))
|
||||
return (m_id - 1) * 4 + 0x10;
|
||||
else if (m_id < 12)
|
||||
return (m_id - 10) * 4;
|
||||
else if (m_id < 14)
|
||||
return (m_id - 12) * 4 + 0x08;
|
||||
else if (m_id < 17)
|
||||
return (m_id - 14) * 4 + 0x34;
|
||||
else
|
||||
return (m_id - 17) * 4 + 0x64;
|
||||
}
|
||||
|
||||
bool Volume::setValue(int idx, double v)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
if (!m_dev->readReg(getOffset(), &data))
|
||||
return false;
|
||||
|
||||
/* mute */
|
||||
if (v == 0x8000) {
|
||||
data = 0x80008000;
|
||||
/* unmute */
|
||||
} else if (v == 0x0000) {
|
||||
data = 0x00000000;
|
||||
/* others */
|
||||
} else {
|
||||
if (idx > 1)
|
||||
data = (data & 0xffff0000) | ((uint32_t)v & 0xffff);
|
||||
else
|
||||
data = (((uint32_t)v & 0xffff) << 16) | (data & 0xffff);
|
||||
}
|
||||
|
||||
return m_dev->writeReg(getOffset(), data);
|
||||
}
|
||||
|
||||
double Volume::getValue(int idx)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
if (!m_dev->readReg(getOffset(), &data))
|
||||
return 0;
|
||||
|
||||
if (idx > 1)
|
||||
return data & 0xffff;
|
||||
else
|
||||
return data >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input L/R balance control:
|
||||
* Path Target Offset
|
||||
* /Mixer/Feature_LRBalance_1 Analog 1/2 in 0x40
|
||||
* /Mixer/Feature_LRBalance_2 Analog 3/4 in 0x44
|
||||
* /Mixer/Feature_LRBalance_3 Analog 5/6 in 0x48
|
||||
* /Mixer/Feature_LRBalance_4 Analog 7/8 in 0x4c
|
||||
* /Mixer/Feature_LRBalance_5 S/PDIF 1/2 in 0x50
|
||||
* /Mixer/Feature_LRBalance_6 ADAT 1/2 in 0x54
|
||||
* /Mixer/Feature_LRBalance_7 ADAT 3/4 in 0x58
|
||||
* /Mixer/Feature_LRBalance_8 ADAT 5/6 in 0x5c
|
||||
* /Mixer/Feature_LRBalance_9 ADAT 7/8 in 0x60
|
||||
*/
|
||||
|
||||
LRBalance::LRBalance(Device &dev, unsigned int id)
|
||||
: Control::Continuous((Device *)&dev)
|
||||
, m_dev(&dev)
|
||||
, m_id(id)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << "Feature_LRBalance_" << id;
|
||||
Control::Continuous::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for L/R Balance " << id;
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for L/R Balance " << id;
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
uint64_t LRBalance::getOffset()
|
||||
{
|
||||
return (m_id - 1) * 4 + 0x40;
|
||||
}
|
||||
|
||||
bool LRBalance::setValue(int idx, double v)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
if (!m_dev->readReg(getOffset(), &data))
|
||||
return false;
|
||||
|
||||
if (idx > 1)
|
||||
data = (data & 0xffff0000) | ((uint32_t)v & 0xffff);
|
||||
else
|
||||
data = (data & 0xffff) | (((uint32_t)v & 0xffff) << 16);
|
||||
|
||||
return m_dev->writeReg(getOffset(), data);
|
||||
}
|
||||
|
||||
double LRBalance::getValue(int idx)
|
||||
{
|
||||
uint32_t data;
|
||||
int16_t val;
|
||||
|
||||
if (!m_dev->readReg(getOffset(), &data))
|
||||
return 0;
|
||||
|
||||
if (idx > 1)
|
||||
val = data & 0xff00;
|
||||
else
|
||||
val = (data >> 16) & 0xff00;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mixer input control:
|
||||
* Path Target Offset (Ana/Strm)
|
||||
* /Mixer/EnhancedMixer_1 Mixer 1/2 out 0x90/0x9c
|
||||
* /Mixer/EnhancedMixer_2 Mixer 3/4 out 0x90/0x9c
|
||||
*/
|
||||
Processing::Processing(Device& dev, unsigned int id)
|
||||
: Control::Continuous((Device *)&dev)
|
||||
, m_dev(&dev)
|
||||
, m_id(id)
|
||||
{
|
||||
std::ostringstream ostrm;
|
||||
ostrm << "EnhancedMixer_" << id;
|
||||
Control::Continuous::setName(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Label for EnhancedMixer " << id;
|
||||
setLabel(ostrm.str());
|
||||
|
||||
ostrm.str("");
|
||||
ostrm << "Description for EnhancedMixer " << id;
|
||||
setDescription(ostrm.str());
|
||||
}
|
||||
|
||||
uint64_t Processing::getOffset(int iPlugNum)
|
||||
{
|
||||
/* Stream inputs */
|
||||
if (iPlugNum != 2)
|
||||
return 0x90;
|
||||
/* Analog inputs */
|
||||
/* S/PDIF inputs */
|
||||
/* ADAT inputs */
|
||||
else
|
||||
return 0x94;
|
||||
}
|
||||
|
||||
bool Processing::setValue(int idx, double v)
|
||||
{
|
||||
int iPlugNum, iAChNum;
|
||||
uint64_t offset;
|
||||
uint32_t data, value, mask;
|
||||
|
||||
iPlugNum = (idx >> 8) & 0x0f;
|
||||
iAChNum = (idx >> 4) & 0x0f;
|
||||
|
||||
offset = getOffset(iPlugNum);
|
||||
if (!m_dev->readReg(offset, &data))
|
||||
return false;
|
||||
|
||||
if (v != 0x00)
|
||||
value = 0;
|
||||
else
|
||||
value = 1;
|
||||
|
||||
/* analog inputs */
|
||||
if (iPlugNum == 1) {
|
||||
mask = 0x01 << (iAChNum / 2);
|
||||
value = value << (iAChNum / 2);
|
||||
|
||||
/* mixer 3/4 out */
|
||||
if (m_id > 1) {
|
||||
mask <<= 4;
|
||||
value <<= 4;
|
||||
}
|
||||
/* stream inputs */
|
||||
} else if (iPlugNum == 2) {
|
||||
mask = 0x01;
|
||||
if (iAChNum > 1) {
|
||||
mask <<= 2;
|
||||
value <<= 2;
|
||||
}
|
||||
if (m_id > 1) {
|
||||
mask <<= 1;
|
||||
value <<= 1;
|
||||
}
|
||||
/* S/PDIF inputs */
|
||||
} else if (iPlugNum == 3) {
|
||||
mask = 0x01 << (iAChNum / 2);
|
||||
value = value << (iAChNum / 2);
|
||||
|
||||
mask <<= 16;
|
||||
value <<= 16;
|
||||
|
||||
/* mixer 3/4 out */
|
||||
if (m_id > 1) {
|
||||
mask <<= 1;
|
||||
value <<= 1;
|
||||
}
|
||||
/* ADAT inputs */
|
||||
} else {
|
||||
mask = 0x01 << (iAChNum / 2);
|
||||
value = value << (iAChNum / 2);
|
||||
|
||||
mask <<= 8;
|
||||
value <<= 8;
|
||||
/* mixer 3/4 out */
|
||||
if (m_id > 1) {
|
||||
mask <<= 4;
|
||||
value <<= 4;
|
||||
}
|
||||
}
|
||||
|
||||
data &= ~mask;
|
||||
data |= value;
|
||||
|
||||
return m_dev->writeReg(offset, data);
|
||||
}
|
||||
|
||||
double Processing::getValue(int idx)
|
||||
{
|
||||
int iPlugNum, iAChNum, shift;
|
||||
uint64_t offset;
|
||||
uint32_t data;
|
||||
double value;
|
||||
|
||||
iPlugNum = (idx >> 8) & 0xF;
|
||||
iAChNum = (idx >> 4) & 0xF;
|
||||
|
||||
offset = getOffset(iPlugNum);
|
||||
|
||||
if (!m_dev->readReg(offset, &data))
|
||||
return false;
|
||||
|
||||
/* analog inputs */
|
||||
if (iPlugNum == 1) {
|
||||
shift = iAChNum / 2;
|
||||
if (m_id > 1)
|
||||
shift += 4;
|
||||
/* stream inputs */
|
||||
} else if (iPlugNum == 2) {
|
||||
shift = 0;
|
||||
if (iAChNum > 1)
|
||||
shift += 1;
|
||||
if (m_id > 1)
|
||||
shift += 2;
|
||||
/* S/PDIF inputs */
|
||||
} else if (iPlugNum == 3) {
|
||||
shift = iAChNum / 2;
|
||||
shift += 16;
|
||||
/* ADAT inputs */
|
||||
} else {
|
||||
shift = iAChNum / 2;
|
||||
shift += 8;
|
||||
if (m_id > 1)
|
||||
shift += 4;
|
||||
}
|
||||
|
||||
if ((data >> shift) & 0x01)
|
||||
value = 0x0000;
|
||||
else
|
||||
value = 0x8000;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace Special
|
||||
} // namespace MAudio
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_MAUDIO_SPECIAL_MIXER_H
|
||||
#define BEBOB_MAUDIO_SPECIAL_MIXER_H
|
||||
|
||||
#include "src/debugmodule/debugmodule.h"
|
||||
#include "libcontrol/BasicElements.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace MAudio {
|
||||
namespace Special {
|
||||
|
||||
class Device;
|
||||
|
||||
class Mixer : public Control::Container
|
||||
{
|
||||
public:
|
||||
Mixer(Device &dev);
|
||||
virtual ~Mixer() {};
|
||||
|
||||
bool initialize(Device &dev);
|
||||
|
||||
virtual std::string getName()
|
||||
{return "Mixer";};
|
||||
virtual bool setName(std::string n)
|
||||
{return false;};
|
||||
|
||||
protected:
|
||||
DECLARE_DEBUG_MODULE;
|
||||
|
||||
private:
|
||||
Device *m_dev;
|
||||
};
|
||||
|
||||
class Selector
|
||||
: public Control::Discrete
|
||||
{
|
||||
public:
|
||||
Selector(Device& dev, unsigned int id);
|
||||
virtual ~Selector() {};
|
||||
|
||||
virtual bool setValue(int idx, int v);
|
||||
virtual int getValue(int idx);
|
||||
|
||||
virtual bool setValue(int v)
|
||||
{return setValue(1, v);};
|
||||
virtual int getValue()
|
||||
{return getValue(1);};
|
||||
virtual int getMinimum()
|
||||
{return 1;};
|
||||
virtual int getMaximum()
|
||||
{return 4;};
|
||||
|
||||
private:
|
||||
uint64_t getOffset();
|
||||
Device *m_dev;
|
||||
unsigned int m_id;
|
||||
};
|
||||
|
||||
class Volume
|
||||
: public Control::Continuous
|
||||
{
|
||||
public:
|
||||
Volume(Device& m_dev, unsigned int id);
|
||||
virtual ~Volume() {};
|
||||
|
||||
virtual bool setValue(int idx, double v);
|
||||
virtual double getValue(int idx);
|
||||
|
||||
virtual bool setValue(double v)
|
||||
{return setValue(1, v);};
|
||||
virtual double getValue()
|
||||
{return getValue(1);};
|
||||
virtual double getMinimum()
|
||||
{return 0x8000;};
|
||||
virtual double getMaximum()
|
||||
{return 0x0000;};
|
||||
|
||||
private:
|
||||
uint64_t getOffset();
|
||||
Device *m_dev;
|
||||
unsigned int m_id;
|
||||
};
|
||||
|
||||
class LRBalance
|
||||
: public Control::Continuous
|
||||
{
|
||||
public:
|
||||
LRBalance(Device& dev, unsigned int id);
|
||||
virtual ~LRBalance() {};
|
||||
|
||||
virtual bool setValue(int idx, double v);
|
||||
virtual double getValue(int idx);
|
||||
|
||||
virtual bool setValue(double v)
|
||||
{return setValue(1, v);};
|
||||
virtual double getValue()
|
||||
{return getValue(1);};
|
||||
virtual double getMinimum()
|
||||
{return -32766;};
|
||||
virtual double getMaximum()
|
||||
{return 32768;};
|
||||
|
||||
private:
|
||||
uint64_t getOffset();
|
||||
Device *m_dev;
|
||||
unsigned int m_id;
|
||||
};
|
||||
|
||||
class Processing
|
||||
: public Control::Continuous
|
||||
{
|
||||
public:
|
||||
Processing(Device& dev, unsigned int id);
|
||||
virtual ~Processing() {};
|
||||
|
||||
virtual bool setValue(int idx, double v);
|
||||
virtual double getValue(int idx);
|
||||
|
||||
virtual bool setValue(double v)
|
||||
{return setValue(1, v);};
|
||||
virtual double getValue()
|
||||
{return getValue(1);};
|
||||
virtual double getMinimum()
|
||||
{return 0x8000;};
|
||||
virtual double getMaximum()
|
||||
{return 0x0000;};
|
||||
|
||||
private:
|
||||
uint64_t getOffset(int iPlugNum);
|
||||
Device *m_dev;
|
||||
unsigned int m_id;
|
||||
};
|
||||
|
||||
} // namespace Special
|
||||
} // namespace MAudio
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif /* BEBOB_MAUDIO_SPECIAL_MIXER_H */
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "firebox_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Presonus {
|
||||
namespace Firebox {
|
||||
|
||||
Device::Device(DeviceManager& d, ffado_smartptr<ConfigRom>(configRom))
|
||||
: BeBoB::Device( d, configRom)
|
||||
{
|
||||
m_intl_clksrc.type = FFADODevice::eCT_Internal;
|
||||
m_intl_clksrc.valid = true;
|
||||
m_intl_clksrc.locked = true;
|
||||
m_intl_clksrc.id = 0x00;
|
||||
m_intl_clksrc.slipping = false;
|
||||
m_intl_clksrc.description = "Internal";
|
||||
|
||||
m_spdif_clksrc.type = FFADODevice::eCT_SPDIF;
|
||||
m_spdif_clksrc.valid = true;
|
||||
m_spdif_clksrc.locked = true;
|
||||
m_spdif_clksrc.id = 0x01;
|
||||
m_spdif_clksrc.slipping = false;
|
||||
m_spdif_clksrc.description = "S/PDIF (Coaxial)";
|
||||
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Presonus::Firebox::Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Presonus::Firebox::Device\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
Device::getSupportedClockSources()
|
||||
{
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_intl_clksrc);
|
||||
r.push_back(m_spdif_clksrc);
|
||||
return r;
|
||||
}
|
||||
|
||||
enum FFADODevice::eClockSourceType
|
||||
Device::getClkSrc()
|
||||
{
|
||||
AVC::SignalSourceCmd cmd(get1394Service());
|
||||
cmd.setCommandType(AVC::AVCCommand::eCT_Status);
|
||||
cmd.setNodeId(getNodeId());
|
||||
cmd.setSubunitType(AVC::eST_Unit);
|
||||
cmd.setSubunitId(0xff);
|
||||
cmd.setVerbose(getDebugLevel());
|
||||
|
||||
AVC::SignalSubunitAddress dst;
|
||||
dst.m_subunitType = AVC::eST_Music;
|
||||
dst.m_subunitId = 0x00;
|
||||
dst.m_plugId = 0x05;
|
||||
cmd.setSignalDestination(dst);
|
||||
|
||||
if (!cmd.fire()) {
|
||||
debugError( "Signal source command failed\n" );
|
||||
return eCT_Invalid;
|
||||
}
|
||||
AVC::SignalAddress* pSyncPlugSignalAddress = cmd.getSignalSource();
|
||||
|
||||
AVC::SignalSubunitAddress* pSyncPlugSubunitAddress
|
||||
= dynamic_cast<AVC::SignalSubunitAddress*>( pSyncPlugSignalAddress );
|
||||
if (pSyncPlugSubunitAddress) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
|
||||
( pSyncPlugSubunitAddress->m_subunitType << 3
|
||||
| pSyncPlugSubunitAddress->m_subunitId ) << 8
|
||||
| pSyncPlugSubunitAddress->m_plugId );
|
||||
return eCT_Internal;
|
||||
}
|
||||
|
||||
AVC::SignalUnitAddress* pSyncPlugUnitAddress
|
||||
= dynamic_cast<AVC::SignalUnitAddress*>( pSyncPlugSignalAddress );
|
||||
if (pSyncPlugUnitAddress) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Sync mode 0x%02x\n",
|
||||
0xff << 8 | pSyncPlugUnitAddress->m_plugId );
|
||||
return eCT_SPDIF;
|
||||
}
|
||||
|
||||
debugError( "Could not retrieve sync mode\n" );
|
||||
return eCT_Invalid;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
Device::getActiveClockSource()
|
||||
{
|
||||
switch (getClkSrc()) {
|
||||
case eCT_Internal:
|
||||
m_intl_clksrc.active = true;
|
||||
m_spdif_clksrc.active = false;
|
||||
return m_intl_clksrc;
|
||||
case eCT_SPDIF:
|
||||
m_intl_clksrc.active = false;
|
||||
m_spdif_clksrc.active = true;
|
||||
return m_spdif_clksrc;
|
||||
default:
|
||||
ClockSource s;
|
||||
s.type = eCT_Invalid;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setActiveClockSource(ClockSource s)
|
||||
{
|
||||
AVC::SignalSourceCmd cmd(get1394Service());
|
||||
cmd.setCommandType(AVC::AVCCommand::eCT_Control);
|
||||
cmd.setNodeId(getNodeId());
|
||||
cmd.setSubunitType(AVC::eST_Unit);
|
||||
cmd.setSubunitId(0xff);
|
||||
cmd.setVerbose(getDebugLevel());
|
||||
|
||||
AVC::SignalSubunitAddress dst;
|
||||
dst.m_subunitType = AVC::eST_Music;
|
||||
dst.m_subunitId = 0x00;
|
||||
dst.m_plugId = 0x05;
|
||||
cmd.setSignalDestination(dst);
|
||||
|
||||
if (s.id == 0x00) {
|
||||
AVC::SignalSubunitAddress src;
|
||||
src.m_subunitType = AVC::eST_Music;
|
||||
src.m_subunitId = 0x00;
|
||||
src.m_plugId = 0x06;
|
||||
cmd.setSignalSource( src );
|
||||
} else {
|
||||
AVC::SignalUnitAddress src;
|
||||
src.m_plugId = 0x83;
|
||||
cmd.setSignalSource(src);
|
||||
}
|
||||
|
||||
if (!cmd.fire()) {
|
||||
debugError( "Signal source command failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Firebox
|
||||
} // namespace Presonus
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_PRESONUS_DEVICE_H
|
||||
#define BEBOB_PRESONUS_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Presonus {
|
||||
namespace Firebox {
|
||||
|
||||
class Device : public BeBoB::Device {
|
||||
public:
|
||||
Device( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~Device();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
private:
|
||||
enum FFADODevice::eClockSourceType getClkSrc();
|
||||
ClockSource m_intl_clksrc;
|
||||
ClockSource m_spdif_clksrc;
|
||||
ClockSource *m_active_clksrc;
|
||||
};
|
||||
|
||||
} // namespace Firebox
|
||||
} // namespace Presonus
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "./inspire1394_avdevice.h"
|
||||
|
||||
#include "libutil/ByteSwap.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Presonus {
|
||||
namespace Inspire1394 {
|
||||
|
||||
Command::Command(Ieee1394Service& ieee1394service)
|
||||
: VendorDependentCmd( ieee1394service )
|
||||
, m_subfunc( 0x00 )
|
||||
, m_idx( 0x00 )
|
||||
, m_arg( 0x00 )
|
||||
{
|
||||
m_companyId = 0x000a92;
|
||||
setSubunitType( AVC::eST_Audio );
|
||||
setSubunitId( 0x00 );
|
||||
}
|
||||
bool Command::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result = true;
|
||||
result &= VendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_subfunc, "Cmd subfunc");
|
||||
result &= se.write(m_idx, "Cmd idx");
|
||||
result &= se.write(m_arg, "Cmd arg");
|
||||
|
||||
return result;
|
||||
}
|
||||
bool Command::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result = true;
|
||||
result &= VendorDependentCmd::deserialize( de );
|
||||
result &= de.read( &m_subfunc);
|
||||
result &= de.read( &m_idx );
|
||||
result &= de.read( &m_arg );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BinaryControl::BinaryControl(Device& parent,
|
||||
ECmdSubfunc subfunc,
|
||||
std::string name, std::string label, std::string desc)
|
||||
: Control::Discrete(&parent)
|
||||
, m_Parent(parent)
|
||||
, m_subfunc( subfunc )
|
||||
{
|
||||
setName(name);
|
||||
setLabel(label);
|
||||
setDescription(desc);
|
||||
}
|
||||
bool BinaryControl::setValue(int idx, int v)
|
||||
{
|
||||
uint8_t val = v;
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,
|
||||
"setValue for type: %d, idx: %d, val: %d\n",
|
||||
m_subfunc, idx, val);
|
||||
|
||||
if ( !m_Parent.setSpecificValue(m_subfunc, idx, val) ) {
|
||||
debugError( "setSpecificValue failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
int BinaryControl::getValue(int idx)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
if ( !m_Parent.getSpecificValue(m_subfunc, idx, &val) ) {
|
||||
debugError( "getSpecificValue failed\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,
|
||||
"getValue for type: %d, idx: %d, val: %d\n",
|
||||
m_subfunc, idx, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
Device::Device(DeviceManager& d, ffado_smartptr<ConfigRom>(configRom))
|
||||
: BeBoB::Device( d, configRom )
|
||||
{
|
||||
addSpecificControls();
|
||||
}
|
||||
Device::~Device(void)
|
||||
{
|
||||
}
|
||||
void Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL,
|
||||
"This is a BeBoB::Presonus::Inspire1394::Device\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
bool Device::addSpecificControls(void)
|
||||
{
|
||||
Control::Container *ctls;
|
||||
BinaryControl *ctl;
|
||||
bool result = true;
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,
|
||||
"Building a PreSonus Inspire1394 mixer...\n");
|
||||
|
||||
ctls = new Control::Container(this, "Preamp");
|
||||
if ( !addElement(ctls) ) {
|
||||
debugWarning("Could not register specific controls to device\n");
|
||||
delete ctls;
|
||||
return false;
|
||||
}
|
||||
|
||||
// RIAA equalization curve for Analog In 3/4
|
||||
ctl = new BinaryControl(*this, ECmdSubfuncPhono,
|
||||
"PhonoSwitch", "Phono Switch", "Phono Switch");
|
||||
result &= ctls->addElement(ctl);
|
||||
|
||||
// 48V for Analog In 1/2
|
||||
ctl = new BinaryControl(*this, ECmdSubfuncPhantom,
|
||||
"PhantomPower", "Phantom Power", "Phantom Power");
|
||||
result &= ctls->addElement(ctl);
|
||||
|
||||
// +20dB for Analog In 1/2
|
||||
ctl = new BinaryControl(*this, ECmdSubfuncBoost,
|
||||
"MicBoost", "Mic Boost", "Mic Boost");
|
||||
result &= ctls->addElement(ctl);
|
||||
|
||||
// Limitter of preamp for Analog In 1/2
|
||||
ctl = new BinaryControl(*this, ECmdSubfuncLimit,
|
||||
"MicLimit", "Mic Limit", "Mic Limit");
|
||||
result &= ctls->addElement(ctl);
|
||||
|
||||
if ( !result ) {
|
||||
debugWarning("Any controls could not be added\n");
|
||||
destroyMixer();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Device::getSpecificValue(ECmdSubfunc subfunc,
|
||||
int idx, uint8_t *val)
|
||||
{
|
||||
Command cmd( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Status );
|
||||
cmd.setNodeId( getConfigRom().getNodeId() );
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
|
||||
cmd.setSubfunc(subfunc);
|
||||
cmd.setIdx(idx);
|
||||
cmd.setArg(0xff);
|
||||
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "Cmd failed\n" );
|
||||
return false;
|
||||
} else if (cmd.getResponse() != AVC::AVCCommand::eR_Implemented ) {
|
||||
debugError("Cmd received error response\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*val = cmd.getArg();
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Device::setSpecificValue(ECmdSubfunc subfunc,
|
||||
int idx, uint8_t val)
|
||||
{
|
||||
Command cmd( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Control );
|
||||
cmd.setNodeId( getConfigRom().getNodeId() );
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
|
||||
cmd.setSubfunc(subfunc);
|
||||
cmd.setIdx(idx);
|
||||
cmd.setArg(val);
|
||||
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "Cmd failed\n" );
|
||||
return false;
|
||||
} else if (cmd.getResponse() != AVC::AVCCommand::eR_Accepted) {
|
||||
debugError("Cmd received error response\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Inspire1394
|
||||
} // namespace Presonus
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_PRESONUS_INSPIRE1394_DEVICE_H
|
||||
#define BEBOB_PRESONUS_INSPIRE1394_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
#include "libavc/general/avc_vendor_dependent_cmd.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Presonus {
|
||||
namespace Inspire1394 {
|
||||
|
||||
enum ECmdSubfunc {
|
||||
ECmdSubfuncPhono = 0,
|
||||
ECmdSubfuncPhantom,
|
||||
ECmdSubfuncBoost,
|
||||
ECmdSubfuncLimit
|
||||
};
|
||||
|
||||
class Device : public BeBoB::Device {
|
||||
public:
|
||||
Device( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~Device();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
bool setSpecificValue(ECmdSubfunc subfunc,
|
||||
int idx, uint8_t val);
|
||||
bool getSpecificValue(ECmdSubfunc subfunc,
|
||||
int idx, uint8_t *val);
|
||||
private:
|
||||
bool addSpecificControls(void);
|
||||
};
|
||||
|
||||
class Command : public AVC::VendorDependentCmd
|
||||
{
|
||||
public:
|
||||
Command( Ieee1394Service& ieee1394service );
|
||||
virtual ~Command() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se);
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCommandName() const
|
||||
{ return "Inspire1394"; }
|
||||
|
||||
virtual void setSubfunc(uint8_t subfunc)
|
||||
{ m_subfunc = subfunc; }
|
||||
virtual void setIdx(int idx)
|
||||
{ m_idx = idx; }
|
||||
virtual void setArg(int arg)
|
||||
{ m_arg = arg; }
|
||||
|
||||
virtual int getArg(void)
|
||||
{ return m_arg; }
|
||||
|
||||
protected:
|
||||
uint8_t m_subfunc;
|
||||
uint8_t m_idx;
|
||||
uint8_t m_arg;
|
||||
};
|
||||
|
||||
class BinaryControl : public Control::Discrete
|
||||
{
|
||||
public:
|
||||
BinaryControl(Device& parent,
|
||||
ECmdSubfunc subfunc,
|
||||
std::string name, std::string label, std::string desc);
|
||||
|
||||
virtual bool setValue(int idx, int val);
|
||||
virtual int getValue(int idx);
|
||||
virtual bool setValue(int val)
|
||||
{ return setValue(0, val); }
|
||||
virtual int getValue(void)
|
||||
{ return getValue(0); }
|
||||
|
||||
virtual int getMinimum() { return 0; };
|
||||
virtual int getMaximum() { return 1; };
|
||||
|
||||
private:
|
||||
Device& m_Parent;
|
||||
ECmdSubfunc m_subfunc;
|
||||
};
|
||||
|
||||
} // namespace Inspire1394
|
||||
} // namespace Presonus
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "__vendor___device.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace __Vendor__ {
|
||||
|
||||
VendorDevice::VendorDevice( Ieee1394Service& ieee1394Service,
|
||||
ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( ieee1394Service, configRom)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::__Vendor__::VendorDevice (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
}
|
||||
|
||||
VendorDevice::~VendorDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
VendorDevice::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "This is a BeBoB::__Vendor__::VendorDevice\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
} // __Vendor__
|
||||
} // BeBoB
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB___VENDOR___DEVICE_H
|
||||
#define BEBOB___VENDOR___DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace __Vendor__ {
|
||||
|
||||
class VendorDevice : public BeBoB::Device {
|
||||
public:
|
||||
VendorDevice( Ieee1394Service& ieee1394Service,
|
||||
ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~VendorDevice();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
};
|
||||
|
||||
} // namespace __Vendor__
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "terratec_cmd.h"
|
||||
|
||||
#include "libutil/ByteSwap.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Terratec {
|
||||
|
||||
TerratecVendorDependentCmd::TerratecVendorDependentCmd(Ieee1394Service& ieee1394service)
|
||||
: VendorDependentCmd( ieee1394service )
|
||||
, m_subfunction ( 0x00 )
|
||||
{
|
||||
m_companyId=0x000aac;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecVendorDependentCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= VendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_subfunction,"TerratecVendorDependentCmd subfunction");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecVendorDependentCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= VendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_subfunction);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
TerratecSyncStateCmd::TerratecSyncStateCmd(Ieee1394Service& ieee1394service)
|
||||
: TerratecVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_subfunction=0x21;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSyncStateCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_syncstate,"TerratecSyncStateCmd m_syncstate");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSyncStateCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_syncstate);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
TerratecStoreMixerSettingsCmd::TerratecStoreMixerSettingsCmd(Ieee1394Service& ieee1394service)
|
||||
: TerratecVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_subfunction=0x22;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecStoreMixerSettingsCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
return TerratecVendorDependentCmd::serialize( se );;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecStoreMixerSettingsCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
return TerratecVendorDependentCmd::deserialize( de );;
|
||||
}
|
||||
|
||||
|
||||
//---------
|
||||
|
||||
TerratecSetMidiRemoteChannelCmd::TerratecSetMidiRemoteChannelCmd(Ieee1394Service& ieee1394service)
|
||||
: TerratecVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_subfunction=0x23;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSetMidiRemoteChannelCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_midichannel,"TerratecSetMidiRemoteChannelCmd m_midichannel");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSetMidiRemoteChannelCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_midichannel);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
TerratecSetMidiControlCmd::TerratecSetMidiControlCmd(Ieee1394Service& ieee1394service)
|
||||
: TerratecVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_subfunction=0x24;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSetMidiControlCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_mixercontrol,"TerratecSetMidiControlCmd m_mixercontrol");
|
||||
result &= se.write(m_midicontroller,"TerratecSetMidiControlCmd m_midicontroller");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSetMidiControlCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_mixercontrol);
|
||||
result &= de.read(&m_midicontroller);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
TerratecSetDefaultRoutingCmd::TerratecSetDefaultRoutingCmd(Ieee1394Service& ieee1394service)
|
||||
: TerratecVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_subfunction=0x25;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSetDefaultRoutingCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_output,"TerratecSetDefaultRoutingCmd m_output");
|
||||
result &= se.write(m_source,"TerratecSetDefaultRoutingCmd m_source");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecSetDefaultRoutingCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_output);
|
||||
result &= de.read(&m_source);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
TerratecDeviceIdCmd::TerratecDeviceIdCmd(Ieee1394Service& ieee1394service)
|
||||
: TerratecVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_subfunction=0x26;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecDeviceIdCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_deviceid,"TerratecDeviceIdCmd m_deviceid");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
TerratecDeviceIdCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= TerratecVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_deviceid);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TERRATECVENDORDEPENDENT_H
|
||||
#define TERRATECVENDORDEPENDENT_H
|
||||
|
||||
#include "libavc/general/avc_generic.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
#include "libavc/general/avc_vendor_dependent_cmd.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Terratec {
|
||||
|
||||
class TerratecVendorDependentCmd: public AVC::VendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecVendorDependentCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecVendorDependentCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecVendorDependentCmd"; }
|
||||
|
||||
protected:
|
||||
byte_t m_subfunction;
|
||||
};
|
||||
|
||||
class TerratecSyncStateCmd: public TerratecVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecSyncStateCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecSyncStateCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecSyncStateCmd"; }
|
||||
|
||||
byte_t m_syncstate;
|
||||
};
|
||||
|
||||
class TerratecStoreMixerSettingsCmd: public TerratecVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecStoreMixerSettingsCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecStoreMixerSettingsCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecStoreMixerSettingsCmd"; }
|
||||
};
|
||||
|
||||
class TerratecSetMidiRemoteChannelCmd: public TerratecVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecSetMidiRemoteChannelCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecSetMidiRemoteChannelCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecSetMidiRemoteChannelCmd"; }
|
||||
|
||||
byte_t m_midichannel;
|
||||
};
|
||||
|
||||
class TerratecSetMidiControlCmd: public TerratecVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecSetMidiControlCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecSetMidiControlCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecSetMidiControlCmd"; }
|
||||
|
||||
byte_t m_mixercontrol;
|
||||
byte_t m_midicontroller;
|
||||
};
|
||||
|
||||
class TerratecSetDefaultRoutingCmd: public TerratecVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecSetDefaultRoutingCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecSetDefaultRoutingCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecSetDefaultRoutingCmd"; }
|
||||
|
||||
byte_t m_output;
|
||||
byte_t m_source;
|
||||
};
|
||||
|
||||
class TerratecDeviceIdCmd: public TerratecVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
TerratecDeviceIdCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~TerratecDeviceIdCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "TerratecDeviceIdCmd"; }
|
||||
|
||||
byte_t m_deviceid;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TERRATECVENDORDEPENDENT_H
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "terratec_device.h"
|
||||
#include "src/bebob/bebob_dl_mgr.h"
|
||||
#include "src/bebob/bebob_dl_bcd.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Terratec {
|
||||
|
||||
Phase88Device::Phase88Device(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d, configRom)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Terratec::Phase88Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
updateClockSources();
|
||||
}
|
||||
|
||||
Phase88Device::~Phase88Device()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Phase88Device::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Terratec::Phase88Device\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
bool
|
||||
Phase88Device::discover()
|
||||
{
|
||||
BeBoB::BootloaderManager blMgr( get1394Service(), getNodeId() );
|
||||
blMgr.printInfoRegisters();
|
||||
if (blMgr.getSoftwareVersion() < 0x01120d1f) {
|
||||
debugError("The firmware of this Phase88 device is too old. Please update the firmware.\n");
|
||||
return false;
|
||||
}
|
||||
return BeBoB::Device::discover();
|
||||
}
|
||||
|
||||
void
|
||||
Phase88Device::updateClockSources() {
|
||||
m_internal_clocksource.type = FFADODevice::eCT_Internal;
|
||||
m_internal_clocksource.valid = true;
|
||||
m_internal_clocksource.locked = true;
|
||||
m_internal_clocksource.id = 0;
|
||||
m_internal_clocksource.slipping = false;
|
||||
m_internal_clocksource.description = "Internal";
|
||||
|
||||
m_spdif_clocksource.type = FFADODevice::eCT_SPDIF;
|
||||
m_spdif_clocksource.valid = true;
|
||||
m_spdif_clocksource.locked = false;
|
||||
m_spdif_clocksource.id = 1;
|
||||
m_spdif_clocksource.slipping = false;
|
||||
m_spdif_clocksource.description = "S/PDIF";
|
||||
|
||||
m_wordclock_clocksource.type = FFADODevice::eCT_WordClock;
|
||||
m_wordclock_clocksource.valid = true;
|
||||
m_wordclock_clocksource.locked = false;
|
||||
m_wordclock_clocksource.id = 2;
|
||||
m_wordclock_clocksource.slipping = false;
|
||||
m_wordclock_clocksource.description = "WordClock";
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
Phase88Device::getActiveClockSource() {
|
||||
int fb_extsync_value = getSelectorFBValue(8);
|
||||
int fb_syncsource_value = getSelectorFBValue(9);
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,
|
||||
"Selectors: 0x%02X 0x%02X\n",
|
||||
fb_extsync_value, fb_syncsource_value);
|
||||
|
||||
|
||||
if(fb_syncsource_value == 0) {
|
||||
return m_internal_clocksource;
|
||||
} else {
|
||||
if(fb_extsync_value == 0) {
|
||||
return m_spdif_clocksource;
|
||||
} else {
|
||||
return m_wordclock_clocksource;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Phase88Device::setActiveClockSource(ClockSource s) {
|
||||
if(s.id == m_internal_clocksource.id) {
|
||||
return setSelectorFBValue(9, 0);
|
||||
}
|
||||
if(s.id == m_spdif_clocksource.id) {
|
||||
bool retval = true;
|
||||
retval &= setSelectorFBValue(8, 0);
|
||||
retval &= setSelectorFBValue(9, 1);
|
||||
return retval;
|
||||
}
|
||||
if(s.id == m_wordclock_clocksource.id) {
|
||||
bool retval = true;
|
||||
retval &= setSelectorFBValue(8, 1);
|
||||
retval &= setSelectorFBValue(9, 1);
|
||||
return retval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
Phase88Device::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_internal_clocksource);
|
||||
r.push_back(m_spdif_clocksource);
|
||||
r.push_back(m_wordclock_clocksource);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
Phase88Device::getConfigurationIdSyncMode()
|
||||
{
|
||||
uint8_t fb_extsync_value = getSelectorFBValue(8);
|
||||
uint8_t fb_syncsource_value = getSelectorFBValue(9);
|
||||
return (fb_extsync_value & 0x01) | ((fb_syncsource_value << 1) & 0x01);
|
||||
}
|
||||
|
||||
} // namespace Terratec
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_TERRATEC_DEVICE_H
|
||||
#define BEBOB_TERRATEC_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Terratec {
|
||||
|
||||
class Phase88Device : public BeBoB::Device {
|
||||
public:
|
||||
Phase88Device( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~Phase88Device();
|
||||
|
||||
virtual bool discover();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
// override these since the phase88 does not support
|
||||
// the usual clock source selection mechanism
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
protected:
|
||||
virtual uint16_t getConfigurationIdSyncMode();
|
||||
|
||||
private:
|
||||
void updateClockSources();
|
||||
ClockSource m_internal_clocksource;
|
||||
ClockSource m_spdif_clocksource;
|
||||
ClockSource m_wordclock_clocksource;
|
||||
};
|
||||
|
||||
} // namespace Terratec
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "yamaha_avdevice.h"
|
||||
#include "yamaha_cmd.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Yamaha {
|
||||
|
||||
GoDevice::GoDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
: BeBoB::Device( d, configRom)
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created BeBoB::Yamaha::GoDevice (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
updateClockSources();
|
||||
}
|
||||
|
||||
GoDevice::~GoDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GoDevice::showDevice()
|
||||
{
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "This is a BeBoB::Yamaha::GoDevice\n");
|
||||
BeBoB::Device::showDevice();
|
||||
}
|
||||
|
||||
bool
|
||||
GoDevice::updateClockSources()
|
||||
{
|
||||
int err;
|
||||
|
||||
m_internal_clocksource.type = FFADODevice::eCT_Internal;
|
||||
m_internal_clocksource.valid = true;
|
||||
m_internal_clocksource.active = false;
|
||||
m_internal_clocksource.locked = true;
|
||||
m_internal_clocksource.id = 0;
|
||||
m_internal_clocksource.slipping = false;
|
||||
m_internal_clocksource.description = "Internal";
|
||||
|
||||
m_spdif_clocksource.type = FFADODevice::eCT_SPDIF;
|
||||
m_spdif_clocksource.valid = true;
|
||||
m_spdif_clocksource.active = false;
|
||||
m_spdif_clocksource.locked = false;
|
||||
m_spdif_clocksource.id = 1;
|
||||
m_spdif_clocksource.slipping = false;
|
||||
m_spdif_clocksource.description = "S/PDIF";
|
||||
|
||||
/* detect digital input */
|
||||
YamahaDigInDetectCmd cmd ( get1394Service() );
|
||||
cmd.setCommandType( AVC::AVCCommand::eCT_Status );
|
||||
cmd.setNodeId( getConfigRom().getNodeId() );
|
||||
cmd.setVerbose( getDebugLevel() );
|
||||
if ( !cmd.fire() ) {
|
||||
debugError( "YamahaDigInDetectCmd failed\n" );
|
||||
return false;
|
||||
} else if (cmd.m_digin == 0) {
|
||||
m_spdif_clocksource.locked = true;
|
||||
}
|
||||
|
||||
/* get current clock source */
|
||||
err = getSelectorFBValue(4);
|
||||
if (err < 0)
|
||||
return err;
|
||||
else if (err > 0) {
|
||||
m_active_clocksource = &m_spdif_clocksource;
|
||||
m_spdif_clocksource.active = true;
|
||||
} else {
|
||||
m_active_clocksource = &m_internal_clocksource;
|
||||
m_internal_clocksource.active = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
GoDevice::getActiveClockSource()
|
||||
{
|
||||
if (!updateClockSources()) {
|
||||
ClockSource s;
|
||||
s.type = eCT_Invalid;
|
||||
return s;
|
||||
}
|
||||
return *m_active_clocksource;
|
||||
}
|
||||
|
||||
bool
|
||||
GoDevice::setActiveClockSource(ClockSource s)
|
||||
{
|
||||
if (!updateClockSources())
|
||||
return false;
|
||||
|
||||
if ((s.id > 0) || (!m_spdif_clocksource.locked))
|
||||
return false;
|
||||
return setSelectorFBValue(4, s.id);
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
GoDevice::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
r.push_back(m_internal_clocksource);
|
||||
r.push_back(m_spdif_clocksource);
|
||||
return r;
|
||||
}
|
||||
} // namespace Yamaha
|
||||
} // namespace BeBoB
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB.
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BEBOB_YAMAHA_DEVICE_H
|
||||
#define BEBOB_YAMAHA_DEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bebob/bebob_avdevice.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Yamaha {
|
||||
|
||||
class GoDevice : public BeBoB::Device {
|
||||
public:
|
||||
GoDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~GoDevice();
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
// override these since the go series does not support
|
||||
// the usual clock source selection mechanism
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
private:
|
||||
bool updateClockSources();
|
||||
ClockSource m_internal_clocksource;
|
||||
ClockSource m_spdif_clocksource;
|
||||
ClockSource *m_active_clocksource;
|
||||
};
|
||||
|
||||
} // namespace Yamaha
|
||||
} // namespace BeBoB
|
||||
|
||||
#endif
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "yamaha_cmd.h"
|
||||
|
||||
#include "libutil/ByteSwap.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace AVC;
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Yamaha {
|
||||
|
||||
YamahaVendorDependentCmd::YamahaVendorDependentCmd(Ieee1394Service& ieee1394service)
|
||||
: VendorDependentCmd( ieee1394service )
|
||||
, m_subfunction ( 0x00 )
|
||||
{
|
||||
/* company id is different between commands */
|
||||
m_companyId = 0x000000;
|
||||
}
|
||||
|
||||
bool
|
||||
YamahaVendorDependentCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= VendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_subfunction,"YamahaVendorDependentCmd subfunction");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
YamahaVendorDependentCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= VendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_subfunction);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
YamahaSyncStateCmd::YamahaSyncStateCmd(Ieee1394Service& ieee1394service)
|
||||
: YamahaVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_companyId = 0x010203;
|
||||
m_subfunction = 0x21;
|
||||
m_syncstate = 0x00;
|
||||
}
|
||||
|
||||
bool
|
||||
YamahaSyncStateCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
result &= YamahaVendorDependentCmd::serialize( se );
|
||||
result &= se.write(m_syncstate,"YamahaSyncStateCmd m_syncstate");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
YamahaSyncStateCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
bool result=true;
|
||||
result &= YamahaVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&m_syncstate);
|
||||
return result;
|
||||
}
|
||||
|
||||
//---------
|
||||
|
||||
YamahaDigInDetectCmd::YamahaDigInDetectCmd(Ieee1394Service& ieee1394service)
|
||||
: YamahaVendorDependentCmd( ieee1394service )
|
||||
{
|
||||
m_companyId = 0x0007f5;
|
||||
m_subfunction = 0x00;
|
||||
m_digin = 0x00;
|
||||
}
|
||||
|
||||
bool
|
||||
YamahaDigInDetectCmd::serialize( Util::Cmd::IOSSerialize& se )
|
||||
{
|
||||
bool result=true;
|
||||
uint8_t buf[] = {0x00, 0x01};
|
||||
|
||||
result &= YamahaVendorDependentCmd::serialize( se );
|
||||
result &= se.write(buf[0], "YamahaDigInDetectCmd Unknown 1");
|
||||
result &= se.write(buf[1], "YamahaDigInDetectCmd Unknown 2");
|
||||
result &= se.write(m_digin, "YamahaDigInDetectCmd m_digin");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
YamahaDigInDetectCmd::deserialize( Util::Cmd::IISDeserialize& de )
|
||||
{
|
||||
uint8_t tmp;
|
||||
bool result = true;
|
||||
|
||||
result &= YamahaVendorDependentCmd::deserialize( de );
|
||||
result &= de.read(&tmp);
|
||||
result &= de.read(&tmp);
|
||||
result &= de.read(&m_digin);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2013 by Takashi Sakamoto
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef YAMAHA_VENDOR_DEPENDENT_H
|
||||
#define YAMAHA_VENDOR_DEPENDENT_H
|
||||
|
||||
#include "libavc/general/avc_generic.h"
|
||||
#include "libutil/cmd_serialize.h"
|
||||
#include "libavc/general/avc_vendor_dependent_cmd.h"
|
||||
|
||||
namespace BeBoB {
|
||||
namespace Yamaha {
|
||||
|
||||
class YamahaVendorDependentCmd: public AVC::VendorDependentCmd
|
||||
{
|
||||
public:
|
||||
YamahaVendorDependentCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~YamahaVendorDependentCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "YamahaVendorDependentCmd"; }
|
||||
|
||||
protected:
|
||||
byte_t m_subfunction;
|
||||
};
|
||||
|
||||
class YamahaSyncStateCmd: public YamahaVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
YamahaSyncStateCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~YamahaSyncStateCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "YamahaSyncStateCmd"; }
|
||||
|
||||
byte_t m_syncstate;
|
||||
};
|
||||
|
||||
class YamahaDigInDetectCmd: public YamahaVendorDependentCmd
|
||||
{
|
||||
public:
|
||||
YamahaDigInDetectCmd(Ieee1394Service& ieee1394service);
|
||||
virtual ~YamahaDigInDetectCmd() {};
|
||||
|
||||
virtual bool serialize( Util::Cmd::IOSSerialize& se );
|
||||
virtual bool deserialize( Util::Cmd::IISDeserialize& de );
|
||||
|
||||
virtual const char* getCmdName() const
|
||||
{ return "YamahaDigInDetectCmd"; }
|
||||
|
||||
byte_t m_digin;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // YAMAHA_VENDOR_DEPENDENT_H
|
|
@ -0,0 +1,571 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bounce/bounce_avdevice.h"
|
||||
|
||||
#include "libieee1394/configrom.h"
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
#include "libutil/Configuration.h"
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
|
||||
#include "devicemanager.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include "libutil/ByteSwap.h"
|
||||
|
||||
namespace Bounce {
|
||||
|
||||
Device::Device( DeviceManager& d, ffado_smartptr< ConfigRom >( configRom ) )
|
||||
: FFADODevice( d, configRom )
|
||||
, m_samplerate (44100)
|
||||
, m_Notifier ( NULL )
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Created Bounce::Device (NodeID %d)\n",
|
||||
getConfigRom().getNodeId() );
|
||||
addOption(Util::OptionContainer::Option("snoopMode",false));
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
Device::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
|
||||
{
|
||||
if(generic) {
|
||||
return false;
|
||||
} else {
|
||||
// check if device is in supported devices list
|
||||
unsigned int vendorId = configRom.getNodeVendorId();
|
||||
unsigned int modelId = configRom.getModelId();
|
||||
|
||||
Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
|
||||
return c.isValid(vme) && vme.driver == Util::Configuration::eD_Bounce;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FFADODevice *
|
||||
Device::createDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
{
|
||||
return new Device(d, configRom );
|
||||
}
|
||||
|
||||
bool
|
||||
Device::discover()
|
||||
{
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "discovering Device (NodeID %d)\n",
|
||||
getNodeId() );
|
||||
|
||||
unsigned int vendorId = getConfigRom().getNodeVendorId();
|
||||
unsigned int modelId = getConfigRom().getModelId();
|
||||
|
||||
Util::Configuration &c = getDeviceManager().getConfiguration();
|
||||
Util::Configuration::VendorModelEntry vme = c.findDeviceVME( vendorId, modelId );
|
||||
|
||||
if (c.isValid(vme) && vme.driver == Util::Configuration::eD_Bounce) {
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "found %s %s\n",
|
||||
vme.vendor_name.c_str(),
|
||||
vme.model_name.c_str());
|
||||
} else {
|
||||
debugWarning("Using generic Bounce support for unsupported device '%s %s'\n",
|
||||
getConfigRom().getVendorName().c_str(), getConfigRom().getModelName().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Device::getSamplingFrequency( ) {
|
||||
return m_samplerate;
|
||||
}
|
||||
|
||||
bool Device::setSamplingFrequency( int s ) {
|
||||
if (s) {
|
||||
m_samplerate=s;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSourceVector
|
||||
Device::getSupportedClockSources() {
|
||||
FFADODevice::ClockSourceVector r;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::setActiveClockSource(ClockSource s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FFADODevice::ClockSource
|
||||
Device::getActiveClockSource() {
|
||||
ClockSource s;
|
||||
return s;
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
Device::getSupportedSamplingFrequencies()
|
||||
{
|
||||
std::vector<int> frequencies;
|
||||
return frequencies;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Device::lock() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Device::unlock() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Device::showDevice()
|
||||
{
|
||||
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "\nI am the bouncedevice, the bouncedevice I am...\n" );
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Vendor : %s\n", getConfigRom().getVendorName().c_str());
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Model : %s\n", getConfigRom().getModelName().c_str());
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Node : %d\n", getNodeId());
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "GUID : 0x%016llX\n", getConfigRom().getGuid());
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "\n" );
|
||||
}
|
||||
|
||||
bool
|
||||
Device::addPortsToProcessor(
|
||||
Streaming::StreamProcessor *processor,
|
||||
Streaming::Port::E_Direction direction) {
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to processor\n");
|
||||
|
||||
std::string id=std::string("dev?");
|
||||
if(!getOption("id", id)) {
|
||||
debugWarning("Could not retrieve id parameter, defauling to 'dev?'\n");
|
||||
}
|
||||
|
||||
int i=0;
|
||||
for (i=0;i<BOUNCE_NB_AUDIO_CHANNELS;i++) {
|
||||
char *buff;
|
||||
asprintf(&buff,"%s%s_Port%d",id.c_str(),direction==Streaming::Port::E_Playback?"p":"c",i);
|
||||
|
||||
Streaming::Port *p=NULL;
|
||||
p=new Streaming::AmdtpAudioPort(
|
||||
*processor,
|
||||
buff,
|
||||
direction,
|
||||
// \todo: streaming backend expects indexing starting from 0
|
||||
// but bebob reports it starting from 1. Decide where
|
||||
// and how to handle this (pp: here)
|
||||
i,
|
||||
0,
|
||||
Streaming::AmdtpPortInfo::E_MBLA
|
||||
);
|
||||
|
||||
if (!p) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
|
||||
}
|
||||
free(buff);
|
||||
}
|
||||
|
||||
for (i=0;i<BOUNCE_NB_MIDI_CHANNELS;i++) {
|
||||
char *buff;
|
||||
asprintf(&buff,"%s_Midi%s%d",id.c_str(),direction==Streaming::Port::E_Playback?"Out":"In",i);
|
||||
|
||||
Streaming::Port *p=NULL;
|
||||
p=new Streaming::AmdtpMidiPort(
|
||||
*processor,
|
||||
buff,
|
||||
direction,
|
||||
// \todo: streaming backend expects indexing starting from 0
|
||||
// but bebob reports it starting from 1. Decide where
|
||||
// and how to handle this (pp: here)
|
||||
BOUNCE_NB_AUDIO_CHANNELS,
|
||||
i,
|
||||
Streaming::AmdtpPortInfo::E_Midi
|
||||
);
|
||||
|
||||
if (!p) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
|
||||
}
|
||||
free(buff);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::prepare() {
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Preparing Device...\n" );
|
||||
|
||||
bool snoopMode=false;
|
||||
if(!getOption("snoopMode", snoopMode)) {
|
||||
debugWarning("Could not retrieve snoopMode parameter, defauling to false\n");
|
||||
}
|
||||
|
||||
// create & add streamprocessors
|
||||
Streaming::StreamProcessor *p;
|
||||
|
||||
p=new Streaming::AmdtpReceiveStreamProcessor(*this,
|
||||
BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
|
||||
|
||||
if(!p->init()) {
|
||||
debugFatal("Could not initialize receive processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addPortsToProcessor(p,
|
||||
Streaming::Port::E_Capture)) {
|
||||
debugFatal("Could not add plug to processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_receiveProcessors.push_back(p);
|
||||
|
||||
// do the transmit processor
|
||||
if (snoopMode) {
|
||||
// we are snooping, so this is receive too.
|
||||
p=new Streaming::AmdtpReceiveStreamProcessor(*this,
|
||||
BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
|
||||
} else {
|
||||
p=new Streaming::AmdtpTransmitStreamProcessor(*this,
|
||||
BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
|
||||
}
|
||||
|
||||
if(!p->init()) {
|
||||
debugFatal("Could not initialize transmit processor %s!\n",
|
||||
(snoopMode?" in snoop mode":""));
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (snoopMode) {
|
||||
if (!addPortsToProcessor(p,
|
||||
Streaming::Port::E_Capture)) {
|
||||
debugFatal("Could not add plug to processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
m_receiveProcessors.push_back(p);
|
||||
} else {
|
||||
if (!addPortsToProcessor(p,
|
||||
Streaming::Port::E_Playback)) {
|
||||
debugFatal("Could not add plug to processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
m_transmitProcessors.push_back(p);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
Device::getStreamCount() {
|
||||
return m_receiveProcessors.size() + m_transmitProcessors.size();
|
||||
}
|
||||
|
||||
Streaming::StreamProcessor *
|
||||
Device::getStreamProcessorByIndex(int i) {
|
||||
if (i<(int)m_receiveProcessors.size()) {
|
||||
return m_receiveProcessors.at(i);
|
||||
} else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
|
||||
return m_transmitProcessors.at(i-m_receiveProcessors.size());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::startStreamByIndex(int i) {
|
||||
if (i<(int)m_receiveProcessors.size()) {
|
||||
int n=i;
|
||||
Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
|
||||
|
||||
// allocate ISO channel
|
||||
int isochannel=allocateIsoChannel(p->getMaxPacketSize());
|
||||
if(isochannel<0) {
|
||||
debugError("Could not allocate iso channel for SP %d\n",i);
|
||||
return false;
|
||||
}
|
||||
p->setChannel(isochannel);
|
||||
|
||||
fb_quadlet_t reg_isoch;
|
||||
// check value of ISO_CHANNEL register
|
||||
if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, ®_isoch)) {
|
||||
debugError("Could not read ISO_CHANNEL register\n");
|
||||
p->setChannel(-1);
|
||||
deallocateIsoChannel(isochannel);
|
||||
return false;
|
||||
}
|
||||
if(reg_isoch != 0xFFFFFFFFUL) {
|
||||
debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
|
||||
p->setChannel(-1);
|
||||
deallocateIsoChannel(isochannel);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write value of ISO_CHANNEL register
|
||||
reg_isoch=isochannel;
|
||||
if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
|
||||
debugError("Could not write ISO_CHANNEL register\n");
|
||||
p->setChannel(-1);
|
||||
deallocateIsoChannel(isochannel);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
|
||||
int n=i-m_receiveProcessors.size();
|
||||
Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
|
||||
|
||||
// allocate ISO channel
|
||||
int isochannel=allocateIsoChannel(p->getMaxPacketSize());
|
||||
if(isochannel<0) {
|
||||
debugError("Could not allocate iso channel for SP %d\n",i);
|
||||
return false;
|
||||
}
|
||||
p->setChannel(isochannel);
|
||||
|
||||
fb_quadlet_t reg_isoch;
|
||||
// check value of ISO_CHANNEL register
|
||||
if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, ®_isoch)) {
|
||||
debugError("Could not read ISO_CHANNEL register\n");
|
||||
p->setChannel(-1);
|
||||
deallocateIsoChannel(isochannel);
|
||||
return false;
|
||||
}
|
||||
if(reg_isoch != 0xFFFFFFFFUL) {
|
||||
debugError("ISO_CHANNEL register != 0xFFFFFFFF (=0x%08X)\n", reg_isoch);
|
||||
p->setChannel(-1);
|
||||
deallocateIsoChannel(isochannel);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write value of ISO_CHANNEL register
|
||||
reg_isoch=isochannel;
|
||||
if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
|
||||
debugError("Could not write ISO_CHANNEL register\n");
|
||||
p->setChannel(-1);
|
||||
deallocateIsoChannel(isochannel);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
debugError("SP index %d out of range!\n",i);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::stopStreamByIndex(int i) {
|
||||
if (i<(int)m_receiveProcessors.size()) {
|
||||
int n=i;
|
||||
Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
|
||||
unsigned int isochannel=p->getChannel();
|
||||
|
||||
fb_quadlet_t reg_isoch;
|
||||
// check value of ISO_CHANNEL register
|
||||
if(!readReg(BOUNCE_REGISTER_TX_ISOCHANNEL, ®_isoch)) {
|
||||
debugError("Could not read ISO_CHANNEL register\n");
|
||||
return false;
|
||||
}
|
||||
if(reg_isoch != isochannel) {
|
||||
debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write value of ISO_CHANNEL register
|
||||
reg_isoch=0xFFFFFFFFUL;
|
||||
if(!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, reg_isoch)) {
|
||||
debugError("Could not write ISO_CHANNEL register\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// deallocate ISO channel
|
||||
if(!deallocateIsoChannel(isochannel)) {
|
||||
debugError("Could not deallocate iso channel for SP\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
p->setChannel(-1);
|
||||
return true;
|
||||
|
||||
} else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
|
||||
int n=i-m_receiveProcessors.size();
|
||||
Streaming::StreamProcessor *p=m_transmitProcessors.at(n);
|
||||
|
||||
unsigned int isochannel=p->getChannel();
|
||||
|
||||
fb_quadlet_t reg_isoch;
|
||||
// check value of ISO_CHANNEL register
|
||||
if(!readReg(BOUNCE_REGISTER_RX_ISOCHANNEL, ®_isoch)) {
|
||||
debugError("Could not read ISO_CHANNEL register\n");
|
||||
return false;
|
||||
}
|
||||
if(reg_isoch != isochannel) {
|
||||
debugError("ISO_CHANNEL register != 0x%08X (=0x%08X)\n", isochannel, reg_isoch);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write value of ISO_CHANNEL register
|
||||
reg_isoch=0xFFFFFFFFUL;
|
||||
if(!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, reg_isoch)) {
|
||||
debugError("Could not write ISO_CHANNEL register\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// deallocate ISO channel
|
||||
if(!deallocateIsoChannel(isochannel)) {
|
||||
debugError("Could not deallocate iso channel for SP (%d)\n",i);
|
||||
return false;
|
||||
}
|
||||
|
||||
p->setChannel(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
debugError("SP index %d out of range!\n",i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// helper functions
|
||||
|
||||
// allocate ISO resources for the SP's
|
||||
int Device::allocateIsoChannel(unsigned int packet_size) {
|
||||
unsigned int bandwidth=8+packet_size;
|
||||
|
||||
int ch=get1394Service().allocateIsoChannelGeneric(bandwidth);
|
||||
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "allocated channel %d, bandwidth %d\n",
|
||||
ch, bandwidth);
|
||||
|
||||
return ch;
|
||||
}
|
||||
// deallocate ISO resources
|
||||
bool Device::deallocateIsoChannel(int channel) {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "freeing channel %d\n",channel);
|
||||
return get1394Service().freeIsoChannel(channel);
|
||||
}
|
||||
|
||||
// I/O functions
|
||||
|
||||
bool
|
||||
Device::readReg(fb_nodeaddr_t offset, fb_quadlet_t *result) {
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX\n", offset);
|
||||
|
||||
if(offset >= BOUNCE_INVALID_OFFSET) {
|
||||
debugError("invalid offset: 0x%016llX\n", offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
|
||||
fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
|
||||
|
||||
if(!get1394Service().read_quadlet( nodeId, addr, result ) ) {
|
||||
debugError("Could not read from node 0x%04X addr 0x%012X\n", nodeId, (unsigned int)addr);
|
||||
return false;
|
||||
}
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Read result: 0x%08X\n", *result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::writeReg(fb_nodeaddr_t offset, fb_quadlet_t data) {
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, data: 0x%08X\n",
|
||||
offset, data);
|
||||
|
||||
if(offset >= BOUNCE_INVALID_OFFSET) {
|
||||
debugError("invalid offset: 0x%016llX\n", offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
|
||||
fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
|
||||
|
||||
if(!get1394Service().write_quadlet( nodeId, addr, data ) ) {
|
||||
debugError("Could not write to node 0x%04X addr 0x%012X\n", nodeId, (unsigned int)addr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::readRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Reading base register offset 0x%08llX, length %u\n",
|
||||
offset, length);
|
||||
|
||||
if(offset >= BOUNCE_INVALID_OFFSET) {
|
||||
debugError("invalid offset: 0x%016llX\n", offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
|
||||
fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
|
||||
|
||||
if(!get1394Service().read( nodeId, addr, length, data ) ) {
|
||||
debugError("Could not read from node 0x%04X addr 0x%012llX\n", nodeId, addr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Device::writeRegBlock(fb_nodeaddr_t offset, fb_quadlet_t *data, size_t length) {
|
||||
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Writing base register offset 0x%08llX, length: %u\n",
|
||||
offset, length);
|
||||
|
||||
if(offset >= BOUNCE_INVALID_OFFSET) {
|
||||
debugError("invalid offset: 0x%016llX\n", offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_nodeaddr_t addr=BOUNCE_REGISTER_BASE + offset;
|
||||
fb_nodeid_t nodeId=getNodeId() | 0xFFC0;
|
||||
|
||||
if(!get1394Service().write( nodeId, addr, length, data ) ) {
|
||||
debugError("Could not write to node 0x%04X addr 0x%012llX\n", nodeId, addr);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOUNCEDEVICE_H
|
||||
#define BOUNCEDEVICE_H
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "libavc/avc_definitions.h"
|
||||
#include "libavc/general/avc_extended_cmd_generic.h"
|
||||
|
||||
#include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h"
|
||||
#include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h"
|
||||
#include "libstreaming/amdtp/AmdtpPort.h"
|
||||
#include "libstreaming/amdtp/AmdtpPortInfo.h"
|
||||
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
#include "ffadodevice.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define BOUNCE_REGISTER_BASE 0x0000FFFFE0000000ULL
|
||||
#define BOUNCE_REGISTER_LENGTH (4*256)
|
||||
#define BOUNCE_REGISTER_TX_ISOCHANNEL 0x10
|
||||
#define BOUNCE_REGISTER_RX_ISOCHANNEL 0x14
|
||||
#define BOUNCE_INVALID_OFFSET 0xFFFFF00000000000ULL
|
||||
|
||||
#define BOUNCE_NB_AUDIO_CHANNELS 4
|
||||
|
||||
// don't define more than 8 midi channels!
|
||||
#define BOUNCE_NB_MIDI_CHANNELS 2
|
||||
|
||||
class ConfigRom;
|
||||
class DeviceManager;
|
||||
|
||||
namespace Util {
|
||||
class Configuration;
|
||||
}
|
||||
|
||||
namespace Bounce {
|
||||
|
||||
class Device : public FFADODevice {
|
||||
private:
|
||||
class BounceNotifier;
|
||||
public:
|
||||
Device( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual ~Device();
|
||||
|
||||
static bool probe( Util::Configuration&, ConfigRom& configRom, bool generic = false );
|
||||
static FFADODevice * createDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
virtual bool discover();
|
||||
|
||||
virtual bool setSamplingFrequency( int samplingFrequency );
|
||||
virtual int getSamplingFrequency( );
|
||||
|
||||
virtual ClockSourceVector getSupportedClockSources();
|
||||
virtual bool setActiveClockSource(ClockSource);
|
||||
virtual ClockSource getActiveClockSource();
|
||||
|
||||
virtual std::vector<int> getSupportedSamplingFrequencies();
|
||||
|
||||
virtual bool prepare();
|
||||
virtual bool lock();
|
||||
virtual bool unlock();
|
||||
|
||||
virtual int getStreamCount();
|
||||
|
||||
virtual Streaming::StreamProcessor *getStreamProcessorByIndex(int i);
|
||||
|
||||
virtual bool startStreamByIndex(int i);
|
||||
virtual bool stopStreamByIndex(int i);
|
||||
|
||||
virtual void showDevice();
|
||||
|
||||
protected:
|
||||
unsigned int m_samplerate;
|
||||
|
||||
// streaming stuff
|
||||
typedef std::vector< Streaming::StreamProcessor * > StreamProcessorVector;
|
||||
StreamProcessorVector m_receiveProcessors;
|
||||
StreamProcessorVector m_transmitProcessors;
|
||||
|
||||
bool addPortsToProcessor(
|
||||
Streaming::StreamProcessor *processor,
|
||||
Streaming::Port::E_Direction direction);
|
||||
|
||||
private: // generic helpers
|
||||
int allocateIsoChannel(unsigned int packet_size);
|
||||
bool deallocateIsoChannel(int channel);
|
||||
|
||||
protected: // I/O helpers
|
||||
// quadlet read/write routines
|
||||
bool readReg(fb_nodeaddr_t, fb_quadlet_t *);
|
||||
bool writeReg(fb_nodeaddr_t, fb_quadlet_t);
|
||||
bool readRegBlock(fb_nodeaddr_t, fb_quadlet_t *, size_t);
|
||||
bool writeRegBlock(fb_nodeaddr_t, fb_quadlet_t *, size_t);
|
||||
|
||||
private:
|
||||
BounceNotifier *m_Notifier;
|
||||
/**
|
||||
* this class reacts on the other side writing to the
|
||||
* hosts address space
|
||||
*/
|
||||
#define BOUNCE_NOTIFIER_BASE_ADDRESS 0x0000FFFFE0000000ULL
|
||||
#define BOUNCE_NOTIFIER_BLOCK_LENGTH 4
|
||||
class BounceNotifier : public Ieee1394Service::ARMHandler
|
||||
{
|
||||
public:
|
||||
BounceNotifier(Device &, nodeaddr_t start);
|
||||
virtual ~BounceNotifier();
|
||||
|
||||
private:
|
||||
Device &m_bouncedevice;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "libstreaming/amdtp/AmdtpReceiveStreamProcessor.h"
|
||||
#include "libstreaming/amdtp/AmdtpTransmitStreamProcessor.h"
|
||||
|
||||
#include "libieee1394/configrom.h"
|
||||
#include "libieee1394/ieee1394service.h"
|
||||
|
||||
#include "libutil/Time.h"
|
||||
|
||||
#include "bounce_slave_avdevice.h"
|
||||
|
||||
#include <libraw1394/raw1394.h>
|
||||
#include <libavc1394/rom1394.h>
|
||||
|
||||
namespace Bounce {
|
||||
|
||||
SlaveDevice::SlaveDevice( DeviceManager& d, ffado_smartptr< ConfigRom >( configRom ) )
|
||||
: Device( d, configRom )
|
||||
{
|
||||
addOption(Util::OptionContainer::Option("isoTimeoutSecs",(int64_t)120));
|
||||
}
|
||||
|
||||
SlaveDevice::~SlaveDevice() {
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
SlaveDevice::probe( Util::Configuration& c, ConfigRom& configRom, bool generic )
|
||||
{
|
||||
// we are always capable of constructing a slave device
|
||||
return true;
|
||||
}
|
||||
|
||||
FFADODevice *
|
||||
SlaveDevice::createDevice(DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ))
|
||||
{
|
||||
return new SlaveDevice(d, configRom );
|
||||
}
|
||||
|
||||
bool
|
||||
SlaveDevice::discover()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SlaveDevice::initMemSpace() {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Initializing memory space...\n");
|
||||
fb_quadlet_t result=0xFFFFFFFFLU;
|
||||
|
||||
// initialize the ISO channel registers
|
||||
// this will write to our own registers
|
||||
if (!writeReg(BOUNCE_REGISTER_TX_ISOCHANNEL, result)) {
|
||||
debugError("Could not initalize ISO channel register for TX\n");
|
||||
return false;
|
||||
}
|
||||
if (!writeReg(BOUNCE_REGISTER_RX_ISOCHANNEL, result)) {
|
||||
debugError("Could not initalize ISO channel register for TX\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// set everything such that we can be discovered
|
||||
m_original_config_rom = save_config_rom( get1394Service().getHandle() );
|
||||
|
||||
if ( init_config_rom( get1394Service().getHandle() ) < 0 ) {
|
||||
debugError("Could not initalize local config rom\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// refresh our config rom cache
|
||||
if ( !getConfigRom().initialize() ) {
|
||||
// \todo If a PHY on the bus is in power safe mode then
|
||||
// the config rom is missing. So this might be just
|
||||
// such this case and we can safely skip it. But it might
|
||||
// be there is a real software problem on our side.
|
||||
// This should be handled more carefuly.
|
||||
debugError( "Could not reread config rom from device (node id %d).\n",
|
||||
getNodeId() );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SlaveDevice::restoreMemSpace() {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Restoring memory space...\n");
|
||||
restore_config_rom( get1394Service().getHandle(), m_original_config_rom);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SlaveDevice::lock() {
|
||||
debugOutput(DEBUG_LEVEL_VERBOSE, "Locking node %d\n", getNodeId());
|
||||
|
||||
// get a notifier to handle device notifications
|
||||
nodeaddr_t notify_address;
|
||||
notify_address = get1394Service().findFreeARMBlock(
|
||||
BOUNCE_REGISTER_BASE,
|
||||
BOUNCE_REGISTER_LENGTH,
|
||||
BOUNCE_REGISTER_LENGTH);
|
||||
|
||||
if (notify_address == 0xFFFFFFFFFFFFFFFFLLU) {
|
||||
debugError("Could not find free ARM block for notification\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Notifier=new SlaveDevice::BounceSlaveNotifier(*this, notify_address);
|
||||
|
||||
if(!m_Notifier) {
|
||||
debugError("Could not allocate notifier\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!get1394Service().registerARMHandler(m_Notifier)) {
|
||||
debugError("Could not register notifier\n");
|
||||
delete m_Notifier;
|
||||
m_Notifier=NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// (re)initialize the memory space
|
||||
if (!initMemSpace()) {
|
||||
debugError("Could not initialize memory space\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SlaveDevice::unlock() {
|
||||
// (re)initialize the memory space
|
||||
if (!restoreMemSpace()) {
|
||||
debugError("Could not restore memory space\n");
|
||||
return false;
|
||||
}
|
||||
get1394Service().unregisterARMHandler(m_Notifier);
|
||||
delete m_Notifier;
|
||||
m_Notifier=NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SlaveDevice::prepare() {
|
||||
debugOutput(DEBUG_LEVEL_NORMAL, "Preparing SlaveDevice...\n" );
|
||||
|
||||
// create & add streamprocessors
|
||||
Streaming::StreamProcessor *p;
|
||||
|
||||
p = new Streaming::AmdtpReceiveStreamProcessor(*this,
|
||||
BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
|
||||
|
||||
if(!p->init()) {
|
||||
debugFatal("Could not initialize receive processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addPortsToProcessor(p,
|
||||
Streaming::Port::E_Capture)) {
|
||||
debugFatal("Could not add plug to processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_receiveProcessors.push_back(p);
|
||||
|
||||
// do the transmit processor
|
||||
p = new Streaming::AmdtpTransmitStreamProcessor(*this,
|
||||
BOUNCE_NB_AUDIO_CHANNELS+(BOUNCE_NB_MIDI_CHANNELS?1:0));
|
||||
|
||||
if(!p->init()) {
|
||||
debugFatal("Could not initialize transmit processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addPortsToProcessor(p,
|
||||
Streaming::Port::E_Playback)) {
|
||||
debugFatal("Could not add plug to processor!\n");
|
||||
delete p;
|
||||
return false;
|
||||
}
|
||||
m_transmitProcessors.push_back(p);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this has to wait until the ISO channel numbers are written
|
||||
bool
|
||||
SlaveDevice::startStreamByIndex(int i) {
|
||||
|
||||
if (i<(int)m_receiveProcessors.size()) {
|
||||
int n=i;
|
||||
Streaming::StreamProcessor *p=m_receiveProcessors.at(n);
|
||||
|
||||
// the other side sends on this channel
|
||||
nodeaddr_t iso_channel_offset = BOUNCE_REGISTER_RX_ISOCHANNEL;
|
||||
iso_channel_offset += ((unsigned)n)*4;
|
||||
|
||||
if (!waitForRegisterNotEqualTo(iso_channel_offset, 0xFFFFFFFFLU)) {
|
||||
debugError("Timeout waiting for stream %d to get an ISO channel\n",i);
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_quadlet_t result;
|
||||
// this will read from our own registers
|
||||
if (!readReg(iso_channel_offset, &result)) {
|
||||
debugError("Could not read ISO channel register for stream %d\n",i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set ISO channel
|
||||
p->setChannel(result);
|
||||
|
||||
return true;
|
||||
|
||||
} else if (i<(int)m_receiveProcessors.size() + (int)m_transmitProcessors.size()) {
|
||||
int n=i-m_receiveProcessors.size();
|
||||
Streaming::StreamProcessor *p = m_transmitProcessors.at(n);
|
||||
|
||||
// the other side sends on this channel
|
||||
nodeaddr_t iso_channel_offset = BOUNCE_REGISTER_TX_ISOCHANNEL;
|
||||
iso_channel_offset += ((unsigned)n)*4;
|
||||
|
||||
if (!waitForRegisterNotEqualTo(iso_channel_offset, 0xFFFFFFFF)) {
|
||||
debugError("Timeout waiting for stream %d to get an ISO channel\n",i);
|
||||
return false;
|
||||
}
|
||||
|
||||
fb_quadlet_t result;
|
||||
// this will read from our own registers
|
||||
if (!readReg(iso_channel_offset, &result)) {
|
||||
debugError("Could not read ISO channel register for stream %d\n",i);
|
||||
return false;
|
||||
}
|
||||
|
||||
// set ISO channel
|
||||
p->setChannel(result);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
debugError("SP index %d out of range!\n",i);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
SlaveDevice::stopStreamByIndex(int i) {
|
||||
// nothing special to do I guess...
|
||||
return false;
|
||||
}
|
||||
|
||||
// helpers
|
||||
bool
|
||||
SlaveDevice::waitForRegisterNotEqualTo(nodeaddr_t offset, fb_quadlet_t v) {
|
||||
debugOutput( DEBUG_LEVEL_VERBOSE, "Waiting for StreamProcessor streams to start running...\n");
|
||||
// we have to wait until all streamprocessors indicate that they are running
|
||||
// i.e. that there is actually some data stream flowing
|
||||
int timeoutSecs=120;
|
||||
if(!getOption("isoTimeoutSecs", timeoutSecs)) {
|
||||
debugWarning("Could not retrieve isoTimeoutSecs parameter, defauling to 120secs\n");
|
||||
}
|
||||
|
||||
int wait_cycles=timeoutSecs*10; // two seconds
|
||||
|
||||
fb_quadlet_t reg=v;
|
||||
|
||||
while ((v == reg) && wait_cycles) {
|
||||
wait_cycles--;
|
||||
if (!readReg(offset,®)) {
|
||||
debugError("Could not read register\n");
|
||||
return false;
|
||||
}
|
||||
SleepRelativeUsec(100000);
|
||||
}
|
||||
|
||||
if(!wait_cycles) { // timout has occurred
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// configrom helpers
|
||||
// FIXME: should be changed into a better framework
|
||||
|
||||
|
||||
struct SlaveDevice::configrom_backup
|
||||
SlaveDevice::save_config_rom(raw1394handle_t handle)
|
||||
{
|
||||
int retval;
|
||||
struct configrom_backup tmp;
|
||||
/* get the current rom image */
|
||||
retval=raw1394_get_config_rom(handle, tmp.rom, 0x100, &tmp.rom_size, &tmp.rom_version);
|
||||
// tmp.rom_size=rom1394_get_size(tmp.rom);
|
||||
// printf("save_config_rom get_config_rom returned %d, romsize %d, rom_version %d:\n",retval,tmp.rom_size,tmp.rom_version);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int
|
||||
SlaveDevice::restore_config_rom(raw1394handle_t handle, struct SlaveDevice::configrom_backup old)
|
||||
{
|
||||
int retval;
|
||||
// int i;
|
||||
|
||||
quadlet_t current_rom[0x100];
|
||||
size_t current_rom_size;
|
||||
unsigned char current_rom_version;
|
||||
|
||||
retval=raw1394_get_config_rom(handle, current_rom, 0x100, ¤t_rom_size, ¤t_rom_version);
|
||||
// printf("restore_config_rom get_config_rom returned %d, romsize %d, rom_version %d:\n",retval,current_rom_size,current_rom_version);
|
||||
|
||||
// printf("restore_config_rom restoring to romsize %d, rom_version %d:\n",old.rom_size,old.rom_version);
|
||||
|
||||
retval = raw1394_update_config_rom(handle, old.rom, old.rom_size, current_rom_version);
|
||||
// printf("restore_config_rom update_config_rom returned %d\n",retval);
|
||||
|
||||
/* get the current rom image */
|
||||
retval=raw1394_get_config_rom(handle, current_rom, 0x100, ¤t_rom_size, ¤t_rom_version);
|
||||
current_rom_size = rom1394_get_size(current_rom);
|
||||
// printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,current_rom_size,current_rom_version);
|
||||
// for (i = 0; i < current_rom_size; i++)
|
||||
// {
|
||||
// if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
|
||||
// printf(" %08x", CondSwapFromBus32(current_rom[i]));
|
||||
// }
|
||||
// printf("\n");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
SlaveDevice::init_config_rom(raw1394handle_t handle)
|
||||
{
|
||||
int retval, i;
|
||||
quadlet_t rom[0x100];
|
||||
size_t rom_size;
|
||||
unsigned char rom_version;
|
||||
rom1394_directory dir;
|
||||
char *leaf;
|
||||
|
||||
/* get the current rom image */
|
||||
retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
|
||||
rom_size = rom1394_get_size(rom);
|
||||
// printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,rom_size,rom_version);
|
||||
// for (i = 0; i < rom_size; i++)
|
||||
// {
|
||||
// if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
|
||||
// printf(" %08x", CondSwapFromBus32(rom[i]));
|
||||
// }
|
||||
// printf("\n");
|
||||
|
||||
/* get the local directory */
|
||||
rom1394_get_directory( handle, raw1394_get_local_id(handle) & 0x3f, &dir);
|
||||
|
||||
/* change the vendor description for kicks */
|
||||
i = strlen(dir.textual_leafs[0]);
|
||||
strncpy(dir.textual_leafs[0], FFADO_BOUNCE_SERVER_VENDORNAME " ", i);
|
||||
|
||||
dir.vendor_id=FFADO_BOUNCE_SERVER_VENDORID;
|
||||
dir.model_id=FFADO_BOUNCE_SERVER_MODELID;
|
||||
|
||||
/* update the rom */
|
||||
retval = rom1394_set_directory(rom, &dir);
|
||||
// printf("rom1394_set_directory returned %d, romsize %d:",retval,rom_size);
|
||||
// for (i = 0; i < rom_size; i++)
|
||||
// {
|
||||
// if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
|
||||
// printf(" %08x", CondSwapFromBus32(rom[i]));
|
||||
// }
|
||||
// printf("\n");
|
||||
|
||||
/* free the allocated mem for the textual leaves */
|
||||
rom1394_free_directory( &dir);
|
||||
|
||||
/* add an AV/C unit directory */
|
||||
dir.unit_spec_id = FFADO_BOUNCE_SERVER_SPECID;
|
||||
dir.unit_sw_version = 0x00010001;
|
||||
leaf = (char*)FFADO_BOUNCE_SERVER_MODELNAME;
|
||||
dir.nr_textual_leafs = 1;
|
||||
dir.textual_leafs = &leaf;
|
||||
|
||||
/* manipulate the rom */
|
||||
retval = rom1394_add_unit( rom, &dir);
|
||||
|
||||
/* get the computed size of the rom image */
|
||||
rom_size = rom1394_get_size(rom);
|
||||
|
||||
// printf("rom1394_add_unit_directory returned %d, romsize %d:",retval,rom_size);
|
||||
// for (i = 0; i < rom_size; i++)
|
||||
// {
|
||||
// if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
|
||||
// printf(" %08x", CondSwapFromBus32(rom[i]));
|
||||
// }
|
||||
// printf("\n");
|
||||
//
|
||||
/* convert computed rom size from quadlets to bytes before update */
|
||||
rom_size *= sizeof(quadlet_t);
|
||||
retval = raw1394_update_config_rom(handle, rom, rom_size, rom_version);
|
||||
// printf("update_config_rom returned %d\n",retval);
|
||||
|
||||
retval=raw1394_get_config_rom(handle, rom, 0x100, &rom_size, &rom_version);
|
||||
// printf("get_config_rom returned %d, romsize %d, rom_version %d:",retval,rom_size,rom_version);
|
||||
// for (i = 0; i < rom_size; i++)
|
||||
// {
|
||||
// if (i % 4 == 0) printf("\n0x%04x:", CSR_CONFIG_ROM+i*4);
|
||||
// printf(" %08x", CondSwapFromBus32(rom[i]));
|
||||
// }
|
||||
// printf("\n");
|
||||
|
||||
// printf("You need to reload your ieee1394 modules to reset the rom.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// the notifier
|
||||
|
||||
SlaveDevice::BounceSlaveNotifier::BounceSlaveNotifier(SlaveDevice &d, nodeaddr_t start)
|
||||
: ARMHandler(d.get1394Service(), start, BOUNCE_REGISTER_LENGTH,
|
||||
RAW1394_ARM_READ | RAW1394_ARM_WRITE, // allowed operations
|
||||
0, //RAW1394_ARM_READ | RAW1394_ARM_WRITE, // operations to be notified of
|
||||
0) // operations that are replied to by us (instead of kernel)
|
||||
, m_bounceslavedevice(d)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SlaveDevice::BounceSlaveNotifier::~BounceSlaveNotifier()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // end of namespace Bounce
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2008 by Pieter Palmers
|
||||
* Copyright (C) 2005-2008 by Daniel Wagner
|
||||
*
|
||||
* This file is part of FFADO
|
||||
* FFADO = Free FireWire (pro-)audio drivers for Linux
|
||||
*
|
||||
* FFADO is based upon FreeBoB
|
||||
*
|
||||
* 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) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FFADO_BOUNCESLAVEDEVICE__
|
||||
#define __FFADO_BOUNCESLAVEDEVICE__
|
||||
|
||||
#include "debugmodule/debugmodule.h"
|
||||
#include "bounce_avdevice.h"
|
||||
|
||||
#define FFADO_MAX_NAME_LEN 256
|
||||
|
||||
#define FFADO_BOUNCE_SERVER_VENDORNAME "FFADO Server"
|
||||
#define FFADO_BOUNCE_SERVER_MODELNAME "ffado-server"
|
||||
|
||||
// NOTE: this is currently free, but it is not really allowed to use
|
||||
#define FFADO_BOUNCE_SERVER_VENDORID 0x000B0001
|
||||
#define FFADO_BOUNCE_SERVER_MODELID 0x000B0001
|
||||
#define FFADO_BOUNCE_SERVER_SPECID 0x000B0001
|
||||
|
||||
namespace Bounce {
|
||||
|
||||
class SlaveDevice : public Device {
|
||||
class BounceSlaveNotifier;
|
||||
public:
|
||||
|
||||
SlaveDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ) );
|
||||
virtual ~SlaveDevice();
|
||||
|
||||
static bool probe( Util::Configuration&, ConfigRom& configRom, bool generic = false );
|
||||
static FFADODevice * createDevice( DeviceManager& d, ffado_smartptr<ConfigRom>( configRom ));
|
||||
|
||||
bool discover();
|
||||
bool prepare();
|
||||
bool lock();
|
||||
bool unlock();
|
||||
|
||||
bool startStreamByIndex(int i);
|
||||
bool stopStreamByIndex(int i);
|
||||
|
||||
private:
|
||||
bool waitForRegisterNotEqualTo(nodeaddr_t offset, fb_quadlet_t v);
|
||||
bool initMemSpace();
|
||||
bool restoreMemSpace();
|
||||
|
||||
private: // configrom shit
|
||||
|
||||
struct configrom_backup {
|
||||
quadlet_t rom[0x100];
|
||||
size_t rom_size;
|
||||
unsigned char rom_version;
|
||||
};
|
||||
struct configrom_backup m_original_config_rom;
|
||||
|
||||
struct configrom_backup
|
||||
save_config_rom(raw1394handle_t handle);
|
||||
int restore_config_rom(raw1394handle_t handle, struct configrom_backup old);
|
||||
int init_config_rom(raw1394handle_t handle);
|
||||
|
||||
private:
|
||||
BounceSlaveNotifier *m_Notifier;
|
||||
/**
|
||||
* this class reacts on the other side writing to the
|
||||
* hosts address space
|
||||
*/
|
||||
class BounceSlaveNotifier : public Ieee1394Service::ARMHandler
|
||||
{
|
||||
public:
|
||||
BounceSlaveNotifier(SlaveDevice &, nodeaddr_t start);
|
||||
virtual ~BounceSlaveNotifier();
|
||||
|
||||
private:
|
||||
SlaveDevice &m_bounceslavedevice;
|
||||
};
|
||||
};
|
||||
|
||||
} // end of namespace Bounce
|
||||
|
||||
#endif /* __FFADO_BOUNCESLAVEDEVICE__ */
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue