Import Upstream version 2.4.7

This commit is contained in:
denghao 2023-03-22 10:57:21 +08:00
commit 4c2bbe068f
522 changed files with 211627 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
cache/
.sconsign.dblite
config.h
config_debug.h
libffado.pc
version.h
*.pyc
*.o
*.os
*.so

9
AUTHORS Normal file
View File

@ -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>

2
ChangeLog Normal file
View File

@ -0,0 +1,2 @@
REMARK: Please use the SVN commit messages as replacement for ChangeLog

339
LICENSE.GPLv2 Normal file
View File

@ -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.

674
LICENSE.GPLv3 Normal file
View File

@ -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
NEWS Normal file
View File

340
README Normal file
View File

@ -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

992
SConstruct Normal file
View File

@ -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, 300466 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

0
TODO Normal file
View File

1768
admin/config.guess vendored Normal file

File diff suppressed because it is too large Load Diff

45
admin/dbus.py Normal file
View File

@ -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

237
admin/doxygen.py Normal file
View File

@ -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")

113
admin/pkgconfig.py Normal file
View File

@ -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

50
admin/pyuic.py Normal file
View File

@ -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

50
admin/pyuic4.py Normal file
View File

@ -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

51
admin/pyuic5.py Normal file
View File

@ -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

45
admin/scanreplace.py Normal file
View File

@ -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

284
config.h.in Normal file
View File

@ -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

46
config_debug.h.in Normal file
View File

@ -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

861
configuration Normal file
View File

@ -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.
}
);

137
deb/SConscript Normal file
View File

@ -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"))

16
doc/SConscript Normal file
View File

@ -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" )

198
doc/adding_devices.dox Normal file
View File

@ -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 .
*/

View File

@ -0,0 +1,11 @@
/**
@page amdtpdescription The AMDTP StreamProcessor
@author Pieter Palmers <pieterpalmers@users.sourceforge.net>
@section intro Introduction
( still to be written )
*/

7099
doc/class_diagram_1.eps Normal file

File diff suppressed because it is too large Load Diff

34
doc/mainpage.dox Normal file
View File

@ -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.
*/

View File

@ -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

1517
doc/reference.doxygen.in Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -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.

15170
doc/streaming.xmi Normal file

File diff suppressed because it is too large Load Diff

5
libffado.pc.in Normal file
View File

@ -0,0 +1,5 @@
Name: libffado
Description: FFADO
Version: $VERSION
Libs: -L$LIBDIR -lffado
Cflags: -I$INCLUDEDIR

1
libffado/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
ffado.h

68
libffado/60-ffado.rules Normal file
View File

@ -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"

33
libffado/SConscript Normal file
View File

@ -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" ) )

530
libffado/ffado.h.in Normal file
View File

@ -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 */

4
src/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
test-cyclecalc
test-debugmodule
test-dll
test-unittests-util

403
src/DeviceStringParser.cpp Normal file
View File

@ -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);
}

106
src/DeviceStringParser.h Normal file
View File

@ -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__ */

350
src/SConscript Normal file
View File

@ -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 )

View File

@ -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

139
src/bebob/bebob_avdevice.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

693
src/bebob/bebob_avplug.cpp Normal file
View File

@ -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;
}
}

95
src/bebob/bebob_avplug.h Normal file
View File

@ -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

386
src/bebob/bebob_dl_bcd.cpp Normal file
View File

@ -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 );
}

118
src/bebob/bebob_dl_bcd.h Normal file
View File

@ -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

View File

@ -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;
}

312
src/bebob/bebob_dl_codes.h Normal file
View File

@ -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

776
src/bebob/bebob_dl_mgr.cpp Normal file
View File

@ -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;
}

136
src/bebob/bebob_dl_mgr.h Normal file
View File

@ -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

View File

@ -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;
}
}

View File

@ -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

436
src/bebob/bebob_mixer.cpp Normal file
View File

@ -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

158
src/bebob/bebob_mixer.h Normal file
View File

@ -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__ */

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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, &reg) ) {
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, &reg) ) {
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, &reg) ) {
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, &reg) ) {
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

259
src/bebob/maudio/fw410.xml Normal file
View File

@ -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>

157
src/bebob/maudio/fwap.xml Normal file
View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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, &reg_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, &reg_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, &reg_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, &reg_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

View File

@ -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

View File

@ -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,&reg)) {
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, &current_rom_size, &current_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, &current_rom_size, &current_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

View File

@ -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