Index: /tags/2.0-rc2/external/SConscript =================================================================== --- /tags/2.0-rc2/external/SConscript (revision 1299) +++ /tags/2.0-rc2/external/SConscript (revision 1299) @@ -0,0 +1,29 @@ +# +# 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 . +# + +Import( 'env' ) + +env = env.Clone() + +env.SConscript( dirs=["dbus", "libconfig"], exports="env" ) + Index: /tags/2.0-rc2/external/libconfig/libconfig.html =================================================================== --- /tags/2.0-rc2/external/libconfig/libconfig.html (revision 1304) +++ /tags/2.0-rc2/external/libconfig/libconfig.html (revision 1304) @@ -0,0 +1,2527 @@ + + +libconfig + + + + + + + + + +

libconfig

+
+
A Library For Processing Structured Configuration Files
+Version 1.3
+6 April 2008
+



+Mark A. Lindner +
+

+ +
+

Table of Contents

+ +
+ +
+


+ +Next: , +Up: (dir) + +
+ + +

libconfig

+ + + +
+


+ +Next: , +Previous: Top, +Up: Top + +
+ + + + +

1 Introduction

+ +

Libconfig is a library for reading, manipulating, and writing +structured configuration files. The library features a fully +reentrant parser and includes bindings for both the C and C++ +programming languages. + +

The library runs on modern POSIX-compilant systems, such as Linux, +Solaris, and Mac OS X (Darwin), as well as on Microsoft Windows +2000/XP and later (with either Microsoft Visual Studio 2005 or later, +or the GNU toolchain via the MinGW environment). + +

+


+ + +Next: , +Up: Introduction + +
+ + +

1.1 Why Another Configuration File Library?

+ +

There are several open-source configuration file libraries available +as of this writing. This library was written because each of those +libraries falls short in one or more ways. The main features of +libconfig that set it apart from the other libraries are: + +

+ +
+


+ +Next: , +Previous: Why Another Configuration File Library?, +Up: Introduction + +
+ + +

1.2 Using the Library from a C Program

+ +

To use the library from C code, include the following preprocessor +directive in your source files: + +

+
+
+
     #include <libconfig.h>
+
+
+
+
+ +To link with the library, specify `-lconfig' as an argument to the +linker. + +
+


+ + +Next: , +Previous: Using the Library from a C Program, +Up: Introduction + +
+ + +

1.3 Using the Library from a C++ Program

+ +

To use the library from C++, include the following preprocessor +directive in your source files: + +

+
+
+
     #include <libconfig.h++>
+
+
+
+
+ +Or, alternatively: + +
+
+
+
     #include <libconfig.hh>
+
+
+
+
+ +The C++ API classes are defined in the namespace `libconfig', hence the +following statement may optionally be used: + +
+
+
+
     using namespace libconfig;
+
+
+
+
+ +To link with the library, specify `-lconfig++' as an argument to +the linker. + +
+


+ +Next: , +Previous: Using the Library from a C++ Program, +Up: Introduction + +
+ + +

1.4 Multithreading Issues

+ +

Libconfig is fully reentrant; the functions in the library +do not make use of global variables and do not maintain state between +successive calls. Therefore two independent configurations may be safely +manipulated concurrently by two distinct threads. + +

Libconfig is not thread-safe. The library is not aware of +the presence of threads and knows nothing about the host system's +threading model. Therefore, if an instance of a configuration is to be +accessed from multiple threads, it must be suitably protected by +synchronization mechanisms like read-write locks or mutexes; the +standard rules for safe multithreaded access to shared data must be +observed. + +

Libconfig is not async-safe. Calls should not be made into +the library from signal handlers, because some of the C library +routines that it uses may not be async-safe. + +

Libconfig is not guaranteed to be cancel-safe. Since it is +not aware of the host system's threading model, the library does not +contain any thread cancellation points. In most cases this will not be +an issue for multithreaded programs. However, be aware that some of +the routines in the library (namely those that read/write +configurations from/to files or streams) perform I/O using C library +routines which may potentially block; whether these C library routines +are cancel-safe or not depends on the host system. + +

+


+ + +Previous: Multithreading Issues, +Up: Introduction + +
+ + +

1.5 Compiling Using pkg-config

+ +

On UNIX systems you can use the pkg-config utility (version 0.20 +or later) to automatically select the appropriate compiler and linker +switches for libconfig. Ensure that the environment variable +`PKG_CONFIG_PATH' contains the absolute path to the +lib/pkgconfig subdirectory of the libconfig installation. Then, +you can link C programs with libconfig as follows: + +

     gcc `pkg-config --cflags libconfig` myprogram.c -o myprogram \
+         `pkg-config --libs libconfig`
+
+
+
+
+ +And similarly, for C++ programs: + +
     g++ `pkg-config --cflags libconfig++` myprogram.cpp -o myprogram \
+         `pkg-config --libs libconfig++`
+
+
+
+
+Note the backticks in the above examples. + +
+


+ +Next: , +Previous: Introduction, +Up: Top + +
+ + + + +

2 Configuration Files

+ +

Libconfig supports structured, hierarchical configurations. These +configurations can be read from and written to files and manipulated +in memory. + +

A configuration consists of a group of settings, which +associate names with values. A value can be one of the +following: + +

+ +

Consider the following configuration file for a hypothetical GUI +application, which illustrates all of the elements of the configuration +file grammar. + +

+
+
+

+
     # Example application configuration file
+     
+     version = "1.0";
+     
+     application:
+     {
+       window:
+       {
+         title = "My Application";
+         size = { w = 640; h = 480; };
+         pos = { x = 350; y = 250; };
+       };
+     
+       list = ( ( "abc", 123, true ), 1.234, ( /* an empty list */) );
+     
+       books = ( { title  = "Treasure Island";
+                   author = "Robert Louis Stevenson";
+                   price  = 29.95;
+                   qty    = 5; },
+                 { title  = "Snow Crash";
+                   author = "Neal Stephenson";
+                   price  = 9.99;
+                   qty    = 8; } );
+     
+       misc:
+       {
+         pi = 3.141592654;
+         bigint = 9223372036854775807L;
+         columns = [ "Last Name", "First Name", "MI" ];
+         bitmask = 0x1FC3;
+       };
+     };
+
+
+ +

+
+
+ +Settings can be uniquely identified within the configuration by a +path. The path is a dot-separated sequence of names, beginning +at a top-level group and ending at the setting itself. Each name in +the path is either the name of a setting; if the setting has no name +because it is an element in a list or array, an integer index in +square brackets can be used as the name. + +

For example, in our hypothetical configuration file, the path to the +x setting is application.window.pos.x; the path to the +version setting is simply version; and the path to the +title setting of the second book in the books list is +application.books.[1].title. + +

The datatype of a value is determined from the format of the value +itself. If the value is enclosed in double quotes, it is treated as a +string. If it looks like an integer or floating point number, it is +treated as such. If it is one of the values TRUE, true, +FALSE, or false (or any other mixed-case version of +those tokens, e.g., True or FaLsE), it is treated as a +boolean. If it consists of a comma-separated list of values enclosed +in square brackets, it is treated as an array. And if it consists of a +comma-separated list of values enclosed in parentheses, it is treated +as a list. Any value which does not meet any of these conditions is +considered invalid and results in a parse error. + +

All names are case-sensitive. They may consist only of alphanumeric +characters, dashes (`-'), underscores (`_'), and asterisks +(`*'), and must begin with a letter or asterisk. No other +characters are allowed. + +

In C and C++, integer, 64-bit integer, floating point, and string +values are mapped to the types long, long long, +double, and const char *, respectively. The boolean type +is mapped to int in C and bool in C++. + +

The following sections describe the elements of the configuration file +grammar in additional detail. + +

+


+ +Next: , +Up: Configuration Files + +
+ + +

2.1 Settings

+ +

A setting has the form: + +

name = value ; + +

or: + +

name : value ; + +

The trailing semicolon is required. Whitespace is not significant. + +

The value may be a scalar value, an array, a group, or a list. + +

+


+ +Next: , +Previous: Settings, +Up: Configuration Files + +
+ + +

2.2 Groups

+ +

A group has the form: + +

{ + settings ... +} + +

Groups can contain any number of settings, but each setting must have +a unique name within the group. + +

+


+ +Next: , +Previous: Groups, +Up: Configuration Files + +
+ + +

2.3 Arrays

+ +

An array has the form: + +

[ value, value ... ] + +

An array may have zero or more elements, but the elements must all be +scalar values of the same type. + +

+


+ +Next: , +Previous: Arrays, +Up: Configuration Files + +
+ + +

2.4 Lists

+ +

A list has the form: + +

( value, value ... ) + +

A list may have zero or more elements, each of which can be a scalar +value, an array, a group, or another list. + +

+


+ +Next: , +Previous: Lists, +Up: Configuration Files + +
+ + +

2.5 Integer Values

+ +

Integers can be represented in one of two ways: as a series of one or +more decimal digits (`0' - `9'), with an optional leading +sign character (`+' or `-'); or as a hexadecimal value +consisting of the characters `0x' followed by a series of one or +more hexadecimal digits (`0' - `9', `A' - `F', +`a' - `f'). + +

+


+ + +Next: , +Previous: Integer Values, +Up: Configuration Files + +
+ + +

2.6 64-bit Integer Values

+ +

Long long (64-bit) integers are represented identically to integers, +except that an 'L' character is appended to indicate a 64-bit +value. For example, `0L' indicates a 64-bit integer value 0. + +

+


+ +Next: , +Previous: 64-bit Integer Values, +Up: Configuration Files + +
+ + +

2.7 Floating Point Values

+ +

Floating point values consist of a series of one or more digits, one +decimal point, an optional leading sign character (`+' or +`-'), and an optional exponent. An exponent consists of the +letter `E' or `e', an optional sign character, and a series +of one or more digits. + +

+


+ +Next: , +Previous: Floating Point Values, +Up: Configuration Files + +
+ + +

2.8 Boolean Values

+ +

Boolean values may have one of the following values: `true', +`false', or any mixed-case variation thereof. + +

+


+ +Next: , +Previous: Boolean Values, +Up: Configuration Files + +
+ + +

2.9 String Values

+ +

String values consist of arbitrary text delimited by double +quotes. Literal double quotes can be escaped by preceding them with a +backslash: `\"'. The escape sequences `\\', `\f', +`\n', `\r', and `\t' are also recognized, and have the +usual meaning. No other escape sequences are currently supported. + +

Adjacent strings are automatically concatenated, as in C/C++ source +code. This is useful for formatting very long strings as sequences of +shorter strings. For example, the following constructs are equivalent: + +

+ +
+


+ +Previous: String Values, +Up: Configuration Files + +
+ + +

2.10 Comments

+ +

Three types of comments are allowed within a configuration: + +

+ +

As expected, comment delimiters appearing within quoted strings are +treated as literal text. + +

Comments are ignored when the configuration is read in, so they are +not treated as part of the configuration. Therefore if the +configuration is written back out to a stream, any comments that were +present in the original configuration will be lost. + +

+


+ +Next: , +Previous: Configuration Files, +Up: Top + +
+ + +

3 The C API

+ +

This chapter describes the C library API. The type config_t +represents a configuration, and the type config_setting_t represents +a configuration setting. + +

The boolean values CONFIG_TRUE and CONFIG_FALSE are +macros defined as (1) and (0), respectively. + +

+— Function: void config_init (config_t * config)
+— Function: void config_destroy (config_t * config)
+
+

These functions initialize and destroy the configuration object config. + +

config_init() initializes config as a new, empty +configuration. + +

config_destroy() destroys the configuration config, +deallocating all memory associated with the configuration, but not +including the config_t structure itself. + +

+ +
+— Function: int config_read (config_t * config, FILE * stream)
+
+

This function reads and parses a configuration from the given +stream into the configuration object config. It returns +CONFIG_TRUE on success, or CONFIG_FALSE on failure; the +config_error_text() and config_error_line() +functions, described below, can be used to obtain information about the +error. + +

+ +
+— Function: int config_read_file (config_t * config, const char * filename)
+
+

This function reads and parses a configuration from the file named +filename into the configuration object config. It returns +CONFIG_TRUE on success, or CONFIG_FALSE on failure; the +config_error_text() and config_error_line() functions, +described below, can be used to obtain information about the error. + +

+ +
+— Function: void config_write (const config_t * config, FILE * stream)
+
+

This function writes the configuration config to the given +stream. + +

+ +
+— Function: int config_write_file (config_t * config, const char * filename)
+
+

This function writes the configuration config to the file named +filename. It returns CONFIG_TRUE on success, or +CONFIG_FALSE on failure. + +

+ +
+— Function: const char * config_error_text (const config_t * config)
+— Function: int config_error_line (const config_t * config)
+
+

These functions, which are implemented as macros, return the text and +line number of the parse error, if one occurred during a call to +config_read() or config_read_file(). Storage for the +string returned by config_error_text() is managed by the +library and released automatically when the configuration is +destroyed; the string must not be freed by the caller. + +

+ +
+— Function: void config_set_auto_convert (config_t *config, int flag)
+— Function: int config_get_auto_convert (const config_t *config)
+
+

config_set_auto_convert() enables number auto-conversion for +the configuration config if flag is non-zero, and disables +it otherwise. When this feature is enabled, an attempt to retrieve a +floating point setting's value into an integer (or vice versa), or +store an integer to a floating point setting's value (or vice versa) +will cause the library to silently perform the necessary conversion +(possibly leading to loss of data), rather than reporting failure. By +default this feature is disabled. + +

config_get_auto_convert() returns CONFIG_TRUE if number +auto-conversion is currently enabled for config; otherwise it +returns CONFIG_FALSE. + +

+ +
+— Function: long config_lookup_int (const config_t * config, const char * path)
+— Function: long long config_lookup_int64 (const config_t * config, const char * path)
+— Function: double config_lookup_float (const config_t * config, const char * path)
+— Function: int config_lookup_bool (const config_t * config, const char * path)
+— Function: const char * config_lookup_string (const config_t * config, const char * path)
+
+

These functions locate the setting in the configuration config +specified by the path path. They return the value of the setting +on success, or a 0 or NULL value if the setting was not found or +if the type of the value did not match the type requested. + +

Storage for the string returned by config_lookup_string() is +managed by the library and released automatically when the setting is +destroyed or when the setting's value is changed; the string must not +be freed by the caller. + +

+ +
+— Function: config_setting_t * config_lookup (const config_t * config, const char * path)
+
+

This function locates the setting in the configuration config +specified by the path path. It returns a pointer to the +config_setting_t structure on success, or NULL if the +setting was not found. + +

+ +
+— Function: long config_setting_get_int (const config_setting_t * setting)
+— Function: long long config_setting_get_int64 (const config_setting_t * setting)
+— Function: double config_setting_get_float (const config_setting_t * setting)
+— Function: int config_setting_get_bool (const config_setting_t * setting)
+— Function: const char * config_setting_get_string (const config_setting_t * setting)
+
+

These functions return the value of the given setting. If the +type of the setting does not match the type requested, a 0 or +NULL value is returned. Storage for the string returned by +config_setting_get_string() is managed by the library and +released automatically when the setting is destroyed or when the +setting's value is changed; the string must not be freed by the +caller. + +

+ +
+— Function: int config_setting_set_int (config_setting_t * setting, long value)
+— Function: int config_setting_set_int64 (config_setting_t * setting, long long value)
+— Function: int config_setting_set_float (config_setting_t * setting, double value)
+— Function: int config_setting_set_bool (config_setting_t * setting, int value)
+— Function: int config_setting_set_string (config_setting_t * setting, const char * value)
+
+

These functions set the value of the given setting to +value. On success, they return CONFIG_TRUE. If +the setting does not match the type of the value, they return +CONFIG_FALSE. config_setting_set_string() makes a copy +of the passed string value, so it may be subsequently freed or +modified by the caller without affecting the value of the setting. + +

+ +
+— Function: short config_setting_get_format (config_setting_t * setting)
+— Function: int config_setting_set_format (config_setting_t * setting, short format)
+
+

These functions get and set the external format for the setting setting. + +

+The format must be one of the constants +CONFIG_FORMAT_DEFAULT or CONFIG_FORMAT_HEX. All settings +support the CONFIG_FORMAT_DEFAULT format. The +CONFIG_FORMAT_HEX format specifies hexadecimal formatting for +integer values, and hence only applies to settings of type +CONFIG_TYPE_INT and CONFIG_TYPE_INT64. If format +is invalid for the given setting, it is ignored. + +

config_setting_set_format() returns CONFIG_TRUE on +success and CONFIG_FALSE on failure. + +

+ +
+— Function: config_setting_t * config_setting_get_member (config_setting_t * setting, const char * name)
+
+

This function fetches the child setting named name from the group +setting. It returns the requested setting on success, or +NULL if the setting was not found or if setting is not a +group. + +

+ +
+— Function: config_setting_t * config_setting_get_elem (const config_setting_t * setting, unsigned int idx)
+
+

This function fetches the element at the given index idx in the +setting setting, which must be an array, list, or group. It returns the +requested setting on success, or NULL if idx is out of +range or if setting is not an array, list, or group. + +

+ +
+— Function: long config_setting_get_int_elem (const config_setting_t * setting, int idx)
+— Function: long long config_setting_get_int64_elem (const config_setting_t * setting, int idx)
+— Function: double config_setting_get_float_elem (const config_setting_t * setting, int idx)
+— Function: int config_setting_get_bool_elem (const config_setting_t * setting, int idx)
+— Function: const char * config_setting_get_string_elem (const config_setting_t * setting, int idx)
+
+

These functions return the value at the specified index idx in the +setting setting. If the setting is not an array or list, or if +the type of the element does not match the type requested, or if +idx is out of range, they return 0 or NULL. Storage for +the string returned by config_setting_get_string_elem() is +managed by the library and released automatically when the setting is +destroyed or when its value is changed; the string must not be freed +by the caller. +

+ +
+— Function: config_setting_t * config_setting_set_int_elem (config_setting_t * setting, int idx, long value)
+— Function: config_setting_t * config_setting_set_int64_elem (config_setting_t * setting, int idx, long long value)
+— Function: config_setting_t * config_setting_set_float_elem (config_setting_t * setting, int idx, double value)
+— Function: config_setting_t * config_setting_set_bool_elem (config_setting_t * setting, int idx, int value)
+— Function: config_setting_t * config_setting_set_string_elem (config_setting_t * setting, int idx, const char * value)
+
+

These functions set the value at the specified index idx in the +setting setting to value. If idx is negative, a +new element is added to the end of the array or list. On success, +these functions return a pointer to the setting representing the +element. If the setting is not an array or list, or if the setting is +an array and the type of the array does not match the type of the +value, or if idx is out of range, they return +NULL. config_setting_set_string_elem() makes a copy of +the passed string value, so it may be subsequently freed or +modified by the caller without affecting the value of the setting. +

+ +
+— Function: config_setting_t * config_setting_add (config_setting_t * parent, const char * name, int type)
+
+

This function adds a new child setting or element to the setting +parent, which must be a group, array, or list. If parent +is an array or list, the name parameter is ignored and may be +NULL. + +

The function returns the new setting on success, or NULL if +parent is not a group, array, or list; or if there is already a +child setting of parent named name; or if type is +invalid. +

+ +
+— Function: int config_setting_remove (config_setting_t * parent, const char * name)
+
+

This function removes and destroys the setting named name from +the parent setting parent, which must be a group. Any child +settings of the setting are recursively destroyed as well. + +

The function returns CONFIG_TRUE on success. If parent is +not a group, or if it has no setting with the given name, it returns +CONFIG_FALSE. + +

+ +
+— Function: int config_setting_remove_elem (config_setting_t * parent, unsigned int idx)
+
+

This function removes the child setting at the given index idx from +the setting parent, which must be a group, list, or array. Any +child settings of the removed setting are recursively destroyed as +well. + +

The function returns CONFIG_TRUE on success. If parent is +not a group, list, or array, or if idx is out of range, it returns +CONFIG_FALSE. + +

+ +
+— Function: config_setting_t * config_root_setting (const config_t * config)
+
+

This function returns the root setting for the configuration +config. The root setting is a group. + +

+ +
+— Function: const char * config_setting_name (const config_setting_t * setting)
+
+

This function returns the name of the given setting, or +NULL if the setting has no name. Storage for the returned +string is managed by the library and released automatically when the +setting is destroyed; the string must not be freed by the caller. + +

+ +
+— Function: config_setting_t * config_setting_parent (const config_setting_t * setting)
+
+

This function returns the parent setting of the given setting, +or NULL if setting is the root setting. + +

+ +
+— Function: int config_setting_is_root (const config_setting_t * setting)
+
+

This function returns CONFIG_TRUE if the given setting is +the root setting, and CONFIG_FALSE otherwise. + +

+ +
+— Function: int config_setting_index (const config_setting_t * setting)
+
+

This function returns the index of the given setting within its +parent setting. If setting is the root setting, this function +returns -1. + +

+ +
+— Function: int config_setting_length (const config_setting_t * setting)
+
+

This function returns the number of settings in a group, or the number of +elements in a list or array. For other types of settings, it returns +0. + +

+ +
+— Function: int config_setting_type (const config_setting_t * setting)
+
+

This function returns the type of the given setting. The return +value is one of the constants +CONFIG_TYPE_INT, CONFIG_TYPE_INT64, CONFIG_TYPE_FLOAT, +CONFIG_TYPE_STRING, CONFIG_TYPE_BOOL, +CONFIG_TYPE_ARRAY, CONFIG_TYPE_LIST, or CONFIG_TYPE_GROUP. + +

+ +
+— Function: int config_setting_is_group (const config_setting_t * setting)
+— Function: int config_setting_is_array (const config_setting_t * setting)
+— Function: int config_setting_is_list (const config_setting_t * setting)
+
+

These convenience functions, which are implemented as macros, test if +the setting setting is of a given type. They return +CONFIG_TRUE or CONFIG_FALSE. + +

+ +
+— Function: int config_setting_is_aggregate (const config_setting_t * setting)
+— Function: int config_setting_is_scalar (const config_setting_t * setting)
+— Function: int config_setting_is_number (const config_setting_t * setting)
+
+

These convenience functions, which are implemented as macros, test if +the setting setting is of an aggregate type (a group, array, or +list), of a scalar type (integer, 64-bit integer, floating point, +boolean, or string), and of a number (integer, 64-bit integer, or +floating point), respectively. They return CONFIG_TRUE or +CONFIG_FALSE. + +

+ +
+— Function: unsigned int config_setting_source_line (const config_setting_t * setting)
+
+

This function returns the line number of the configuration file or +stream at which the setting setting was parsed. This information +is useful for reporting application-level errors. If the setting was +not read from a file or stream, or if the line number is otherwise +unavailable, the function returns 0. + +

+ +
+— Function: void config_setting_set_hook (config_setting_t * setting, void * hook)
+— Function: void * config_setting_get_hook (const config_setting_t * setting)
+
+

These functions make it possible to attach arbitrary data to each +setting structure, for instance a “wrapper” or “peer” object written in +another programming language. The destructor function, if one has been +supplied via a call to config_set_destructor(), will be called +by the library to dispose of this data when the setting itself is +destroyed. There is no default destructor. + +

+ +
+— Function: void config_set_destructor (config_t * config, void (* destructor)(void *))
+
+

This function assigns the destructor function destructor for the +configuration config. This function accepts a single void +* argument and has no return value. See +config_setting_set_hook() above for more information. + +

+ +
+


+ + +Next: , +Previous: The C API, +Up: Top + +
+ + +

4 The C++ API

+ +

This chapter describes the C++ library API. The class Config +represents a configuration, and the class Setting represents a +configuration setting. Note that by design, neither of these classes +provides a public copy constructor or assignment operator. Therefore, +instances of these classes may only be passed between functions via +references or pointers. + +

The library defines a group of exceptions, all of which extend the +common base exception ConfigException. + +

A SettingTypeException is thrown when the type of a setting's +value does not match the type requested. + +

A SettingNotFoundException is thrown when a setting is not found. + +

A SettingNameException is thrown when an attempt is made to add +a new setting with a non-unique or invalid name. + +

A ParseException is thrown when a parse error occurs while +reading a configuration from a stream. + +

A FileIOException is thrown when an I/O error occurs while +reading/writing a configuration from/to a file. + +

The remainder of this chapter describes the methods for manipulating +configurations and configuration settings. + +

+— Method on Config: Config ()
+— Method on Config: ~Config ()
+
+

These methods create and destroy Config objects. + +

+ +
+— Method on Config: void read (FILE * stream)
+— Method on Config: void write (FILE * stream)
+
+

The read() method reads and parses a configuration from the given +stream. A ParseException is thrown if a parse error occurs. + +

The write() method writes the configuration to the given stream. + +

+ +
+— Method on Config: void readFile (const char * filename)
+— Method on Config: void writeFile (const char * filename)
+
+

The readFile() method reads and parses a configuration from the file +named filename. A ParseException is thrown if a parse error occurs. A +FileIOException is thrown if the file cannot be read. + +

The writeFile() method writes the configuration to the file +named filename. A FileIOException is thrown if the file cannot +be written. + +

+ +
+— Method on ParseException: const char * getError ()
+— Method on ParseException: int getLine ()
+
+

If a call to readFile() or read() resulted in a +ParseException, these methods can be called on the exception +object to obtain the text and line number of the parse error. Storage +for the string returned by getError() is managed by the +library; the string must not be freed by the caller. + +

+ +
+— Method on Config: void setAutoConvert (bool flag)
+— Method on Config: bool getAutoConvert ()
+
+

setAutoConvert() enables number auto-conversion for the +configuration if flag is true, and disables it +otherwise. When this feature is enabled, an attempt to assign a +floating point setting to an integer (or vice versa), or +assign an integer to a floating point setting (or vice versa) will +cause the library to silently perform the necessary conversion +(possibly leading to loss of data), rather than throwing a +SettingTypeException. By default this feature is disabled. + +

getAutoConvert() returns true if number auto-conversion +is currently enabled for the configuration; otherwise it returns +false. + +

+ +
+— Method on Config: Setting & getRoot ()
+
+

This method returns the root setting for the configuration, which is a group. + +

+ +
+— Method on Config: Setting & lookup (const std::string &path)
+— Method on Config: Setting & lookup (const char * path)
+
+

These methods locate the setting specified by the path path. If +the requested setting is not found, a SettingNotFoundException is +thrown. + +

+ +
+— Method on Config: bool exists (const std::string &path)
+— Method on Config: bool exists (const char *path)
+
+

These methods test if a setting with the given path exists in +the configuration. They return true if the setting exists, and +false otherwise. These methods do not throw exceptions. + +

+ +
+— Method on Config: bool lookupValue (const char *path, bool &value)
+— Method on Config: bool lookupValue (const std::string &path, bool &value)
+ +— Method on Config: bool lookupValue (const char *path, int &value)
+— Method on Config: bool lookupValue (const std::string &path, int &value)
+ +— Method on Config: bool lookupValue (const char *path, unsigned int &value)
+— Method on Config: bool lookupValue (const std::string &path, unsigned int &value)
+ +— Method on Config: bool lookupValue (const char *path, long &value)
+— Method on Config: bool lookupValue (const std::string &path, long &value)
+ +— Method on Config: bool lookupValue (const char *path, long long &value)
+— Method on Config: bool lookupValue (const std::string &path, long long &value)
+ +— Method on Config: bool lookupValue (const char *path, unsigned long &value)
+— Method on Config: bool lookupValue (const std::string &path, unsigned long &value)
+ +— Method on Config: bool lookupValue (const char *path, float &value)
+— Method on Config: bool lookupValue (const std::string &path, float &value)
+ +— Method on Config: bool lookupValue (const char *path, double &value)
+— Method on Config: bool lookupValue (const std::string &path, double &value)
+ +— Method on Config: bool lookupValue (const char *path, const char *&value)
+— Method on Config: bool lookupValue (const std::string &path, const char *&value)
+ +— Method on Config: bool lookupValue (const char *path, std::string &value)
+— Method on Config: bool lookupValue (const std::string &path, std::string &value)
+
+

These are convenience methods for looking up the value of a setting +with the given path. If the setting is found and is of an +appropriate type, the value is stored in value and the method +returns true. Otherwise, value is left unmodified and the +method returns false. These methods do not throw exceptions. + +

Storage for const char * values is managed by the library and +released automatically when the setting is destroyed or when its value +is changed; the string must not be freed by the caller. For safety and +convenience, always assigning string values to a std::string is +suggested. + +

Since these methods have boolean return values and do not throw +exceptions, they can be used within boolean logic expressions. The following +example presents a concise way to look up three values at once and +perform error handling if any of them are not found or are of the +wrong type: + +

+     
+     
+

+
          int var1;
+          double var2;
+          const char *var3;
+          
+          if(config.lookupValue("values.var1", var1)
+             && config.lookupValue("values.var2", var2)
+             && config.lookupValue("values.var3", var3))
+          {
+            // use var1, var2, var3
+          }
+          else
+          {
+            // error handling here
+          }
+     
+
+ +

This approach also takes advantage of the short-circuit evaluation rules +of C++, i.e., if the first lookup fails (returning false), the +remaining lookups are skipped entirely. + +

+ +
+— Method on Setting: operator bool()
+— Method on Setting: operator int()
+— Method on Setting: operator unsigned int()
+— Method on Setting: operator long()
+— Method on Setting: operator unsigned long()
+— Method on Setting: operator long long()
+— Method on Setting: operator unsigned long long()
+— Method on Setting: operator float()
+— Method on Setting: operator double()
+— Method on Setting: operator const char *()
+— Method on Setting: operator std::string()
+
+

These cast operators allow a Setting object to be assigned to a +variable of type bool if it is of type TypeBoolean; +int, unsigned int, long, or unsigned long if it is of +type TypeInt; long long or unsigned long long if +it is of type TypeInt64, float or double if it is of type +TypeFloat; or const char * or std::string if it is +of type TypeString. + +

Storage for const char * return values is managed by the +library and released automatically when the setting is destroyed or +when its value is changed; the string must not be freed by the +caller. For safety and convenience, always assigning string return +values to a std::string is suggested. + +

The following examples demonstrate this usage: + +

+
          long width = config.lookup("application.window.size.w");
+          
+          bool splashScreen = config.lookup("application.splash_screen");
+          
+          std::string title = config.lookup("application.window.title");
+     
+
+ +

Note that certain conversions can lead to loss of precision or +clipping of values, e.g., assigning a negative value to an unsigned +int (in which case the value will be treated as 0), or a +double-precision value to a float. The library does not treat +these lossy conversions as errors. + +

Perhaps surprisingly, the following code in particular will cause a +compiler error: + +

+
          std::string title;
+          .
+          .
+          .
+          title = config.lookup("application.window.title");
+     
+
+ +

This is because the assignment operator of std::string is being +invoked with a Setting & as an argument. The compiler is unable +to make an implicit conversion because both the const char * +and the std::string cast operators of Setting are +equally appropriate. This is not a bug in libconfig; providing +only the const char * cast operator would resolve this +particular ambiguity, but would cause assignments to +std::string like the one in the previous example to produce a +compiler error. (To understand why, see section 11.4.1 of The C++ +Programming Language.) + +

The solution to this problem is to use an explicit conversion that +avoids the construction of an intermediate std::string object, +as follows: + +

+
          std::string title;
+          .
+          .
+          .
+          title = (const char *)config.lookup("application.window.title");
+     
+
+ +

If the assignment is invalid due to a type mismatch, a +SettingTypeException is thrown. + +

+ +
+— Method on Setting: Setting & operator= (bool value)
+— Method on Setting: Setting & operator= (int value)
+— Method on Setting: Setting & operator= (long value)
+— Method on Setting: Setting & operator= (const long long &value)
+— Method on Setting: Setting & operator= (float value)
+— Method on Setting: Setting & operator= (const double &value)
+— Method on Setting: Setting & operator= (const char *value)
+— Method on Setting: Setting & operator= (const std::string &value)
+
+

These assignment operators allow values of type bool, int, +long, long long, float, double, const char *, and +std::string to be assigned to a setting. In the case of strings, +the library makes a copy of the passed string value, so it may +be subsequently freed or modified by the caller without affecting the +value of the setting. + +

If the assignment is invalid due to a type mismatch, a +SettingTypeException is thrown. + +

+ +
+— Method on Setting: Setting & operator[] (int idx)
+— Method on Setting: Setting & operator[] (const std::string &name)
+— Method on Setting: Setting & operator[] (const char *name)
+
+

A Setting object may be subscripted with an integer index +idx if it is an array or list, or with either a string +name or an integer index idx if it is a group. For example, +the following code would produce the string `Last Name' when +applied to the example configuration in Configuration Files. + +

+
          Setting& setting = config.lookup("application.misc");
+          const char *s = setting["columns"][0];
+     
+
+ +

If the setting is not an array, list, or group, a +SettingTypeException is thrown. If the subscript (idx +or name) does not refer to a valid element, a +SettingNotFoundException is thrown. + +

Iterating over a group's child settings with an integer index will +return the settings in the same order that they appear in the +configuration. + +

+ +
+— Method on Setting: bool lookupValue (const char *name, bool &value)
+— Method on Setting: bool lookupValue (const std::string &name, bool &value)
+ +— Method on Setting: bool lookupValue (const char *name, int &value)
+— Method on Setting: bool lookupValue (const std::string &name, int &value)
+ +— Method on Setting: bool lookupValue (const char *name, unsigned int &value)
+— Method on Setting: bool lookupValue (const std::string &name, unsigned int &value)
+ +— Method on Setting: bool lookupValue (const char *name, long long &value)
+— Method on Setting: bool lookupValue (const std::string &name, long long &value)
+ +— Method on Setting: bool lookupValue (const char *name, unsigned long long &value)
+— Method on Setting: bool lookupValue (const std::string &name, unsigned long long &value)
+ +— Method on Setting: bool lookupValue (const char *name, long &value)
+— Method on Setting: bool lookupValue (const std::string &name, long &value)
+ +— Method on Setting: bool lookupValue (const char *name, unsigned long &value)
+— Method on Setting: bool lookupValue (const std::string &name, unsigned long &value)
+ +— Method on Setting: bool lookupValue (const char *name, float &value)
+— Method on Setting: bool lookupValue (const std::string &name, float &value)
+ +— Method on Setting: bool lookupValue (const char *name, double &value)
+— Method on Setting: bool lookupValue (const std::string &name, double &value)
+ +— Method on Setting: bool lookupValue (const char *name, const char *&value)
+— Method on Setting: bool lookupValue (const std::string &name, const char *&value)
+ +— Method on Setting: bool lookupValue (const char *name, std::string &value)
+— Method on Setting: bool lookupValue (const std::string &name, std::string &value)
+
+

These are convenience methods for looking up the value of a child setting +with the given name. If the setting is found and is of an +appropriate type, the value is stored in value and the method +returns true. Otherwise, value is left unmodified and the +method returns false. These methods do not throw exceptions. + +

Storage for const char * values is managed by the library and +released automatically when the setting is destroyed or when its value +is changed; the string must not be freed by the caller. For safety and +convenience, always assigning string values to a std::string is +suggested. + +

Since these methods have boolean return values and do not throw +exceptions, they can be used within boolean logic expressions. The following +example presents a concise way to look up three values at once and +perform error handling if any of them are not found or are of the +wrong type: + +

+     
+     
+

+
          int var1;
+          double var2;
+          const char *var3;
+          
+          if(setting.lookupValue("var1", var1)
+             && setting.lookupValue("var2", var2)
+             && setting.lookupValue("var3", var3))
+          {
+            // use var1, var2, var3
+          }
+          else
+          {
+            // error handling here
+          }
+     
+
+ +

This approach also takes advantage of the short-circuit evaluation +rules of C++, e.g., if the first lookup fails (returning false), the +remaining lookups are skipped entirely. + +

+ +
+— Method on Setting: Setting & add (const std::string &name, Setting::Type type)
+— Method on Setting: Setting & add (const char *name, Setting::Type type)
+
+

These methods add a new child setting with the given name and +type to the setting, which must be a group. They return a +reference to the new setting. If the setting already has a child +setting with the given name, or if the name is invalid, a +SettingNameException is thrown. If the setting is not a group, +a SettingTypeException is thrown. + +

Once a setting has been created, neither its name nor type can be +changed. + +

+ +
+— Method on Setting: Setting & add (Setting::Type type)
+
+

This method adds a new element to the setting, which must be of type +TypeArray or TypeList. If the setting is an array which +currently has zero elements, the type parameter (which must be +TypeInt, TypeInt64, TypeFloat, TypeBool, +or TypeString) determines the type for the array; otherwise it +must match the type of the existing elements in the array. + +

The method returns the new setting on success. If type is a +scalar type, the new setting will have a default value of 0, 0.0, +false, or NULL, depending on the type. + +

The method throws a SettingTypeException if the setting is not +an array or list, or if type is invalid. + +

+ +
+— Method on Setting: void remove (const std::string &name)
+— Method on Setting: void remove (const char *name)
+
+

These methods remove the child setting with the given name from +the setting, which must be a group. Any child settings of the removed +setting are recursively destroyed as well. + +

If the setting is not a group, a SettingTypeException is +thrown. If the setting does not have a child setting with the given +name, a SettingNotFoundException is thrown. + +

+ +
+— Method on Setting: void remove (unsigned int idx)
+
+

This method removes the child setting at the given index idx from +the setting, which must be a group, list, or array. Any child settings +of the removed setting are recursively destroyed as well. + +

If the setting is not a group, list, or array, a +SettingTypeException is thrown. If idx is out of range, +a SettingNotFoundException is thrown. + +

+ +
+— Method on Setting: const char * getName ()
+
+

This method returns the name of the setting, or NULL if the +setting has no name. Storage for the returned string is managed by the +library and released automatically when the setting is destroyed; the +string must not be freed by the caller. For safety and convenience, +consider assigning the return value to a std::string. + +

+ +
+— Method on Setting: std::string getPath ()
+
+

This method returns the complete dot-separated path to the +setting. Settings which do not have a name (list and array elements) +are represented by their index in square brackets. + +

+ +
+— Method on Setting: Setting & getParent ()
+
+

This method returns the parent setting of the setting. If the setting +is the root setting, a SettingNotFoundException is thrown. + +

+ +
+— Method on Setting: bool isRoot ()
+
+

This method returns true if the setting is the root setting, and +false otherwise. + +

+ +
+— Method on Setting: int getIndex ()
+
+

This method returns the index of the setting within its parent +setting. When applied to the root setting, this method returns -1. + +

+ +
+— Method on Setting: Setting::Type getType ()
+
+

This method returns the type of the setting. The +Setting::Type enumeration consists of the following constants: +TypeInt, TypeInt64, TypeFloat, TypeString, +TypeBoolean, TypeArray, TypeList, or +TypeGroup. + +

+ +
+— Method on Setting: Setting::Format getFormat ()
+— Method on Setting: void setFormat (Setting::Format format)
+
+

These methods get and set the external format for the setting. + +

The Setting::Format enumeration consists of the following +constants: FormatDefault, FormatHex. All settings +support the FormatDefault format. The FormatHex format +specifies hexadecimal formatting for integer values, and hence only +applies to settings of type TypeInt and TypeInt64. If +format is invalid for the given setting, it is ignored. + +

+ +
+— Method on Setting: bool exists (const std::string &name)
+— Method on Setting: bool exists (const char *name)
+
+

These methods test if the setting has a child setting with the given +name. They return true if the setting exists, and +false otherwise. These methods do not throw exceptions. + +

+ +
+— Method on Setting: int getLength ()
+
+

This method returns the number of settings in a group, or the number of +elements in a list or array. For other types of settings, it returns +0. + +

+ +
+— Method on Setting: bool isGroup ()
+— Method on Setting: bool isArray ()
+— Method on Setting: bool isList ()
+
+

These convenience methods test if a setting is of a given type. + +

+ +
+— Method on Setting: bool isAggregate ()
+— Method on Setting: bool isScalar ()
+— Method on Setting: bool isNumber ()
+
+

These convenience methods test if a setting is of an aggregate type (a +group, array, or list), of a scalar type (integer, 64-bit integer, +floating point, boolean, or string), and of a number (integer or +floating point), respectively. + +

+ +
+— Method on Setting: unsigned int getSourceLine ()
+
+

This method returns the line number of the configuration file or +stream at which the setting was parsed. This information is useful for +reporting application-level errors. If the setting was not read from a +file or stream, or if the line number is otherwise unavailable, the +method returns 0. + +

+ +
+


+ +Next: , +Previous: The C++ API, +Up: Top + +
+ + +

5 Configuration File Grammar

+ +

Below is the BNF grammar for configuration files. Comments are not part +of the grammar, and hence are not included here. + +

+
+
+
     configuration = setting-list | empty
+     
+     empty =
+     
+     setting-list = setting | setting-list setting
+     
+     setting = name (":" | "=") value ";"
+     
+     value = scalar-value | array | list | group
+     
+     value-list = value | value-list "," value
+     
+     scalar-value = boolean | integer | integer64 | hex | hex64 | float
+                    | string
+     
+     scalar-value-list = scalar-value | scalar-value-list "," scalar-value
+     
+     array = "[" (scalar-value-list | empty) "]"
+     
+     list = "(" (value-list | empty) ")"
+     
+     group = "{" (setting-list | empty) "}"
+
+
+
+
+
+Terminals are defined below as regular expressions: +
+
+
+

boolean +([Tt][Rr][Uu][Ee])|([Ff][Aa][Ll][Ss][Ee]) +
string +\"([^\"\\]|\\.)*\" +
name +[A-Za-z\*][-A-Za-z0-9_\*]* +
integer +[-+]?[0-9]+ +
integer64 +[-+]?[0-9]+L(L)? +
hex +0[Xx][0-9A-Fa-f]+ +
hex64 +0[Xx][0-9A-Fa-f]+L(L)? +
float +([-+]?([0-9]*)?\.[0-9]*([eE][-+]?[0-9]+)?)|([-+]([0-9]+)(\.[0-9]*)?[eE][-+]?[0-9]+) +
+ +

+


+ +Next: , +Previous: Configuration File Grammar, +Up: Top + +
+ + +

Appendix A License

+ + + + +
GNU LESSER GENERAL PUBLIC LICENSE
+
Version 2.1, February 1999
+ +
+
+
+ +Copyright © 1991, 1999 Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +

Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +

[This is the first released version of the Lesser GPL. It also counts +as the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +

+
+
+
Preamble
+
+
+
+ +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software–to +make sure the software is free for all its users. + +

This license, the Lesser General Public License, applies to some +specially designated software packages–typically libraries–of the Free +Software Foundation and other authors who decide to use it. You can use +it too, but we suggest you first think carefully about whether this +license or the ordinary General Public License is the better strategy to +use in any particular case, based on the explanations below. + +

When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in +new free programs; and that you are informed that you can do these +things. + +

To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + +

For example, if you distribute copies of the library, whether gratis or +for a fee, you must give the recipients all the rights that we gave you. +You must make sure that they, too, receive or can get the source code. +If you link other code with the library, you must provide complete +object files to the recipients, so that they can relink them with the +library after making changes to the library and recompiling it. And you +must show them these terms so they know their rights. + +

We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +

To protect each distributor, we want to make it very clear that there is +no warranty for the free library. Also, if the library is modified by +someone else and passed on, the recipients should know that what they +have is not the original version, so that the original author's +reputation will not be affected by problems that might be introduced by +others. + +

Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license +obtained for a version of the library must be consistent with the full +freedom of use specified in this license. + +

Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for +certain libraries in order to permit linking those libraries into +non-free programs. + +

When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the entire +combination fits its criteria of freedom. The Lesser General Public +License permits more lax criteria for linking other code with the +library. + +

We call this license the “Lesser” General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many libraries. +However, the Lesser license provides advantages in certain special +circumstances. + +

For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a +de-facto standard. To achieve this, non-free programs must be allowed +to use the library. A more frequent case is that a free library does +the same job as widely used non-free libraries. In this case, there is +little to gain by limiting the free library to free software only, so we +use the Lesser General Public License. + +

In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, +as well as its variant, the GNU/Linux operating system. + +

Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is linked +with the Library has the freedom and the wherewithal to run that program +using a modified version of the Library. + +

The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +“work based on the library” and a “work that uses the library”. The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +

GNU LESSER GENERAL PUBLIC LICENSE
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+ +
    + +
    +     
    +     
    +
  1. This License Agreement applies to any software library or other program +which contains a notice placed by the copyright holder or other +authorized party saying it may be distributed under the terms of this +Lesser General Public License (also called “this License”). Each +licensee is addressed as “you”. + +

    A “library” means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +

    The “Library”, below, refers to any such software library or work which +has been distributed under these terms. A “work based on the Library” +means either the Library or any derivative work under copyright law: +that is to say, a work containing the Library or a portion of it, either +verbatim or with modifications and/or translated straightforwardly into +another language. (Hereinafter, translation is included without +limitation in the term “modification”.) + +

    “Source code” for a work means the preferred form of the work for making +modifications to it. For a library, 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 library. + +

    Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +a program using the Library is not restricted, and output from such a +program is covered only if its contents constitute a work based on the +Library (independent of the use of the Library in a tool for writing +it). Whether that is true depends on what the Library does and what the +program that uses the Library does. + +

    +     
    +     
    +
  2. You may copy and distribute verbatim copies of the Library's complete +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 +distribute a copy of this License along with the Library. + +

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

    +     
    +     
    +
  3. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such +modifications or work under the terms of Section 1 above, provided that +you also meet all of these conditions: + +
      + +
    1. The modified work must itself be a software library. + +
      +          
      +          
      +
    2. You must cause the files modified to carry prominent notices stating +that you changed the files and the date of any change. + +
      +          
      +          
      +
    3. You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +
      +          
      +          
      +
    4. If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, +other than as an argument passed when the facility is invoked, then you +must make a good faith effort to ensure that, in the event an +application does not supply such function or table, the facility still +operates, and performs whatever part of its purpose remains meaningful. + +

      (For example, a function in a library to compute square roots has a +purpose that is entirely well-defined independent of the application. +Therefore, Subsection 2d requires that any application-supplied function +or table used by this function must be optional: if the application does +not supply it, the square root function must still compute square +roots.) + +

    + +

    These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. + +

    In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of a +storage or distribution medium does not bring the other work under the +scope of this License. + +

    +     
    +     
    +
  4. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so that +they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + +

    Once this change is made in a given copy, it is irreversible for that +copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +

    This option is useful when you wish to copy part of the code of the +Library into a program that is not a library. + +

    +     
    +     
    +
  5. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms +of Sections 1 and 2 above provided that you 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. + +

    If distribution of 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 satisfies the requirement to distribute the +source code, even though third parties are not compelled to copy the +source along with the object code. + +

    +     
    +     
    +
  6. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with +it, is called a “work that uses the Library”. Such a work, in +isolation, is not a derivative work of the Library, and therefore falls +outside the scope of this License. + +

    However, linking a “work that uses the Library” with the Library creates +an executable that is a derivative of the Library (because it contains +portions of the Library), rather than a “work that uses the library”. +The executable is therefore covered by this License. Section 6 states +terms for distribution of such executables. + +

    When a “work that uses the Library” uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be linked +without the Library, or if the work is itself a library. The threshold +for this to be true is not precisely defined by law. + +

    If such an object file uses only numerical parameters, data structure +layouts and accessors, and small macros and small inline functions (ten +lines or less in length), then the use of the object file is +unrestricted, regardless of whether it is legally a derivative work. +(Executables containing this object code plus portions of the Library +will still fall under Section 6.) + +

    Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, whether +or not they are linked directly with the Library itself. + +

    +     
    +     
    +
  7. As an exception to the Sections above, you may also combine or link a +“work that uses the Library” with the Library to produce a work +containing portions of the Library, and distribute that work under terms +of your choice, provided that the terms permit modification of the work +for the customer's own use and reverse engineering for debugging such +modifications. + +

    You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + +

      + +
      +          
      +          
      +
    1. Accompany the work with the complete corresponding machine-readable +source code for the Library including whatever changes were used in the +work (which must be distributed under Sections 1 and 2 above); and, if +the work is an executable linked with the Library, with the complete +machine-readable “work that uses the Library”, as object code and/or +source code, so that the user can modify the Library and then relink to +produce a modified executable containing the modified Library. (It is +understood that the user who changes the contents of definitions files +in the Library will not necessarily be able to recompile the application +to use the modified definitions.) + +
      +          
      +          
      +
    2. Use a suitable shared library mechanism for linking with the Library. A +suitable mechanism is one that (1) uses at run time a copy of the +library already present on the user's computer system, rather than +copying library functions into the executable, and (2) will operate +properly with a modified version of the library, if the user installs +one, as long as the modified version is interface-compatible with the +version that the work was made with. + +
      +          
      +          
      +
    3. Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, +for a charge no more than the cost of performing this distribution. + +
      +          
      +          
      +
    4. If distribution of the work is made by offering access to copy from a +designated place, offer equivalent access to copy the above specified +materials from the same place. + +
      +          
      +          
      +
    5. Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +
    + +

    For an executable, the required form of the “work that uses the Library” +must include any data and utility programs needed for reproducing the +executable from it. However, as a special exception, the materials to +be 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. + +

    It may happen that this requirement contradicts the license restrictions +of other proprietary libraries that do not normally accompany the +operating system. Such a contradiction means you cannot use both them +and the Library together in an executable that you distribute. + +

    +     
    +     
    +
  8. You may place library facilities that are a work based on the Library +side-by-side in a single library together with other library facilities +not covered by this License, and distribute such a combined library, +provided that the separate distribution of the work based on the Library +and of the other library facilities is otherwise permitted, and provided +that you do these two things: + +
      + +
      +          
      +          
      +
    1. Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be +distributed under the terms of the Sections above. + +
      +          
      +          
      +
    2. Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the +accompanying uncombined form of the same work. + +
    + +
    +     
    +     
    +
  9. You may not copy, modify, sublicense, link with, or distribute the +Library except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, link with, or distribute the +Library 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. + +
    +     
    +     
    +
  10. 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 Library or its derivative works. These actions are prohibited by +law if you do not accept this License. Therefore, by modifying or +distributing the Library (or any work based on the Library), you +indicate your acceptance of this License to do so, and all its terms and +conditions for copying, distributing or modifying the Library or works +based on it. + +
    +     
    +     
    +
  11. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + +
    +     
    +     
    +
  12. 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 Library at all. For example, if a patent license +would not permit royalty-free redistribution of the Library 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 Library. + +

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

    +     
    +     
    +
  13. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Library 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. + +
    +     
    +     
    +
  14. The Free Software Foundation may publish revised and/or new versions of +the Lesser 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 Library +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 Library does not specify a license +version number, you may choose any version ever published by the Free +Software Foundation. + +

    +     
    +     
    +
  15. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, 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
    +
    +     
    +     
    + +
  16. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE LIBRARY “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 LIBRARY IS WITH +YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +
    +     
    +     
    +
  17. 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 LIBRARY 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 LIBRARY +(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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+ +

If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of +the ordinary General Public License). + +

To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
+Copyright (C) <year>  <name of author>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+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
+
+
+

Also add information on how to contact you by electronic and paper mail. + +

You should also get your employer (if you work as a programmer) or your +school, if any, to sign a “copyright disclaimer” for the library, if +necessary. Here is a sample; alter the names: + +


+Yoyodyne, Inc., hereby disclaims all copyright interest in the
+library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+<signature of Ty Coon>, 1 April 1990
+Ty Coon, President of Vice
+
+
+

That's all there is to it! + + +

+


+ +Next: , +Previous: License, +Up: Top + +
+ + +

Function Index

+ +
+


+ +Next: , +Previous: Function Index, +Up: Top + +
+ + +

Type Index

+ + + +
+


+ +Previous: Type Index, +Up: Top + +
+ + +

Concept Index

+ + + + + Index: /tags/2.0-rc2/external/libconfig/scanner.h =================================================================== --- /tags/2.0-rc2/external/libconfig/scanner.h (revision 1304) +++ /tags/2.0-rc2/external/libconfig/scanner.h (revision 1304) @@ -0,0 +1,326 @@ +#ifndef libconfig_yyHEADER_H +#define libconfig_yyHEADER_H 1 +#define libconfig_yyIN_HEADER 1 + +#line 6 "scanner.h" + +#line 8 "scanner.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 33 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +int libconfig_yylex_init (yyscan_t* scanner); + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void libconfig_yypop_buffer_state (yyscan_t yyscanner ); + +YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void libconfig_yyfree (void * ,yyscan_t yyscanner ); + +#define libconfig_yywrap(n) 1 +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define COMMENT 1 + +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int libconfig_yylex_destroy (yyscan_t yyscanner ); + +int libconfig_yyget_debug (yyscan_t yyscanner ); + +void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner ); + +void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_in (yyscan_t yyscanner ); + +void libconfig_yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_out (yyscan_t yyscanner ); + +void libconfig_yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int libconfig_yyget_leng (yyscan_t yyscanner ); + +char *libconfig_yyget_text (yyscan_t yyscanner ); + +int libconfig_yyget_lineno (yyscan_t yyscanner ); + +void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner ); + +void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int libconfig_yywrap (yyscan_t yyscanner ); +#else +extern int libconfig_yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int libconfig_yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int libconfig_yylex (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#line 130 "scanner.l" + +#line 325 "scanner.h" +#undef libconfig_yyIN_HEADER +#endif /* libconfig_yyHEADER_H */ Index: /tags/2.0-rc2/external/libconfig/libconfigcpp.cpp =================================================================== --- /tags/2.0-rc2/external/libconfig/libconfigcpp.cpp (revision 1304) +++ /tags/2.0-rc2/external/libconfig/libconfigcpp.cpp (revision 1304) @@ -0,0 +1,969 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2008 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ + +#include "libconfigpp.h" + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include "wincompat.h" + +using namespace libconfig; + +#include + +// --------------------------------------------------------------------------- + +SettingException::SettingException() +{ +} + +SettingException::~SettingException() +{ +} + +// --------------------------------------------------------------------------- + +SettingTypeException::SettingTypeException() +{ +} + +// --------------------------------------------------------------------------- + +SettingNotFoundException::SettingNotFoundException() +{ +} + +// --------------------------------------------------------------------------- + +SettingNameException::SettingNameException() +{ +} + +// --------------------------------------------------------------------------- + +ParseException::ParseException(int line, const char *error) + : _line(line), _error(error) +{ +} + +ParseException::~ParseException() +{ +} + +// --------------------------------------------------------------------------- + +static int __toTypeCode(Setting::Type type) +{ + int typecode; + + switch(type) + { + case Setting::TypeGroup: + typecode = CONFIG_TYPE_GROUP; + break; + + case Setting::TypeInt: + typecode = CONFIG_TYPE_INT; + break; + + case Setting::TypeInt64: + typecode = CONFIG_TYPE_INT64; + break; + + case Setting::TypeFloat: + typecode = CONFIG_TYPE_FLOAT; + break; + + case Setting::TypeString: + typecode = CONFIG_TYPE_STRING; + break; + + case Setting::TypeBoolean: + typecode = CONFIG_TYPE_BOOL; + break; + + case Setting::TypeArray: + typecode = CONFIG_TYPE_ARRAY; + break; + + case Setting::TypeList: + typecode = CONFIG_TYPE_LIST; + break; + + default: + typecode = CONFIG_TYPE_NONE; + } + + return(typecode); +} + +// --------------------------------------------------------------------------- + +static void __constructPath(const Setting &setting, + std::stringstream &path) +{ + // head recursion to print path from root to target + + if(! setting.isRoot()) + { + __constructPath(setting.getParent(), path); + if(path.tellp()) + path << '.'; + + const char *name = setting.getName(); + if(name) + path << name; + else + path << '[' << setting.getIndex() << ']'; + } +} + +// --------------------------------------------------------------------------- + +void Config::ConfigDestructor(void *arg) +{ + delete reinterpret_cast(arg); +} + +// --------------------------------------------------------------------------- + +Config::Config() +{ + config_init(& _config); + config_set_destructor(& _config, ConfigDestructor); +} + +// --------------------------------------------------------------------------- + +Config::~Config() +{ + config_destroy(& _config); +} + +// --------------------------------------------------------------------------- + +void Config::setAutoConvert(bool flag) +{ + config_set_auto_convert(& _config, (flag ? CONFIG_TRUE : CONFIG_FALSE)); +} + +// --------------------------------------------------------------------------- + +bool Config::getAutoConvert() const +{ + return(config_get_auto_convert(& _config) != CONFIG_FALSE); +} + +// --------------------------------------------------------------------------- + +void Config::read(FILE *stream) throw(ParseException) +{ + if(! config_read(& _config, stream)) + throw ParseException(config_error_line(& _config), + config_error_text(& _config)); +} + +// --------------------------------------------------------------------------- + +void Config::write(FILE *stream) const +{ + config_write(& _config, stream); +} + +// --------------------------------------------------------------------------- + +void Config::readFile(const char *filename) throw(FileIOException, + ParseException) +{ + FILE *f = fopen(filename, "rt"); + if(f == NULL) + throw FileIOException(); + try + { + read(f); + fclose(f); + } + catch(ParseException& p) + { + fclose(f); + throw p; + } +} + +// --------------------------------------------------------------------------- + +void Config::writeFile(const char *filename) throw(FileIOException) +{ + if(! config_write_file(& _config, filename)) + throw FileIOException(); +} + +// --------------------------------------------------------------------------- + +Setting & Config::lookup(const char *path) const + throw(SettingNotFoundException) +{ + config_setting_t *s = config_lookup(& _config, path); + if(! s) + throw SettingNotFoundException(); + + return(Setting::wrapSetting(s)); +} + +// --------------------------------------------------------------------------- + +bool Config::exists(const char *path) const throw() +{ + config_setting_t *s = config_lookup(& _config, path); + + return(s != NULL); +} + +// --------------------------------------------------------------------------- + +#define CONFIG_LOOKUP_NO_EXCEPTIONS(P, T, V) \ + try \ + { \ + Setting &s = lookup(P); \ + V = (T)s; \ + return(true); \ + } \ + catch(ConfigException) \ + { \ + return(false); \ + } + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, bool &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, bool, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, long &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, unsigned long &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, unsigned long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, int &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, int, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, unsigned int &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, unsigned int, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, long long &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, long long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, unsigned long long &value) + const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, unsigned long long, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, double &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, double, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, float &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, float, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, const char *&value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, const char *, value); +} + +// --------------------------------------------------------------------------- + +bool Config::lookupValue(const char *path, std::string &value) const throw() +{ + CONFIG_LOOKUP_NO_EXCEPTIONS(path, const char *, value); +} + +// --------------------------------------------------------------------------- + +Setting & Config::getRoot() const +{ + return(Setting::wrapSetting(config_root_setting(& _config))); +} + +// --------------------------------------------------------------------------- + +Setting::Setting(config_setting_t *setting) + : _setting(setting) +{ + switch(config_setting_type(setting)) + { + case CONFIG_TYPE_GROUP: + _type = TypeGroup; + break; + + case CONFIG_TYPE_INT: + _type = TypeInt; + break; + + case CONFIG_TYPE_INT64: + _type = TypeInt64; + break; + + case CONFIG_TYPE_FLOAT: + _type = TypeFloat; + break; + + case CONFIG_TYPE_STRING: + _type = TypeString; + break; + + case CONFIG_TYPE_BOOL: + _type = TypeBoolean; + break; + + case CONFIG_TYPE_ARRAY: + _type = TypeArray; + break; + + case CONFIG_TYPE_LIST: + _type = TypeList; + break; + + case CONFIG_TYPE_NONE: + default: + _type = TypeNone; + break; + } + + switch(config_setting_get_format(setting)) + { + case CONFIG_FORMAT_HEX: + _format = FormatHex; + break; + + case CONFIG_FORMAT_DEFAULT: + default: + _format = FormatDefault; + break; + } +} + +// --------------------------------------------------------------------------- + +Setting::~Setting() throw() +{ + _setting = NULL; +} + +// --------------------------------------------------------------------------- + +void Setting::setFormat(Format format) throw() +{ + if((_type == TypeInt) || (_type == TypeInt64)) + { + if(format == FormatHex) + _format = FormatHex; + else + _format = FormatDefault; + } + else + _format = FormatDefault; +} + +// --------------------------------------------------------------------------- + +Setting::operator bool() const throw(SettingTypeException) +{ + assertType(TypeBoolean); + + return(config_setting_get_bool(_setting) ? true : false); +} + +// --------------------------------------------------------------------------- + +Setting::operator long() const throw(SettingTypeException) +{ + assertType(TypeInt); + + return(config_setting_get_int(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator unsigned long() const throw(SettingTypeException) +{ + assertType(TypeInt); + + long v = config_setting_get_int(_setting); + + if(v < 0) + v = 0; + + return(static_cast(v)); +} + +// --------------------------------------------------------------------------- + +Setting::operator int() const throw(SettingTypeException) +{ + assertType(TypeInt); + + // may cause loss of precision: + return(static_cast(config_setting_get_int(_setting))); +} + +// --------------------------------------------------------------------------- + +Setting::operator unsigned int() const throw(SettingTypeException) +{ + assertType(TypeInt); + + long v = config_setting_get_int(_setting); + + if(v < 0) + v = 0; + + return(static_cast(v)); +} + +// --------------------------------------------------------------------------- + +Setting::operator long long() const throw(SettingTypeException) +{ + assertType(TypeInt64); + + return(config_setting_get_int64(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator unsigned long long() const throw(SettingTypeException) +{ + assertType(TypeInt64); + + long long v = config_setting_get_int64(_setting); + + if(v < INT64_CONST(0)) + v = INT64_CONST(0); + + return(static_cast(v)); +} + +// --------------------------------------------------------------------------- + +Setting::operator double() const throw(SettingTypeException) +{ + assertType(TypeFloat); + + return(config_setting_get_float(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator float() const throw(SettingTypeException) +{ + assertType(TypeFloat); + + // may cause loss of precision: + return(static_cast(config_setting_get_float(_setting))); +} + +// --------------------------------------------------------------------------- + +Setting::operator const char *() const throw(SettingTypeException) +{ + assertType(TypeString); + + return(config_setting_get_string(_setting)); +} + +// --------------------------------------------------------------------------- + +Setting::operator std::string() const throw(SettingTypeException) +{ + assertType(TypeString); + + const char *s = config_setting_get_string(_setting); + + std::string str; + if(s) + str = s; + + return(str); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(bool value) throw(SettingTypeException) +{ + assertType(TypeBoolean); + + config_setting_set_bool(_setting, value); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(long value) throw(SettingTypeException) +{ + assertType(TypeInt); + + config_setting_set_int(_setting, value); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(int value) throw(SettingTypeException) +{ + assertType(TypeInt); + + long cvalue = static_cast(value); + + config_setting_set_int(_setting, cvalue); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const long long &value) + throw(SettingTypeException) +{ + assertType(TypeInt64); + + config_setting_set_int64(_setting, value); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const double &value) throw(SettingTypeException) +{ + assertType(TypeFloat); + + config_setting_set_float(_setting, value); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(float value) throw(SettingTypeException) +{ + assertType(TypeFloat); + + double cvalue = static_cast(value); + + config_setting_set_float(_setting, cvalue); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const char *value) throw(SettingTypeException) +{ + assertType(TypeString); + + config_setting_set_string(_setting, value); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator=(const std::string &value) + throw(SettingTypeException) +{ + assertType(TypeString); + + config_setting_set_string(_setting, value.c_str()); + + return(*this); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator[](int i) const + throw(SettingTypeException, SettingNotFoundException) +{ + if((_type != TypeArray) && (_type != TypeGroup) && (_type != TypeList)) + throw SettingTypeException(); + + config_setting_t *setting = config_setting_get_elem(_setting, i); + + if(! setting) + throw SettingNotFoundException(); + + return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::operator[](const char *key) const + throw(SettingTypeException, SettingNotFoundException) +{ + assertType(TypeGroup); + + config_setting_t *setting = config_setting_get_member(_setting, key); + + if(! setting) + throw SettingNotFoundException(); + + return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +#define SETTING_LOOKUP_NO_EXCEPTIONS(K, T, V) \ + try \ + { \ + Setting &s = operator[](K); \ + V = (T)s; \ + return(true); \ + } \ + catch(ConfigException) \ + { \ + return(false); \ + } + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, bool &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, bool, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, long &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, unsigned long &value) + const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, unsigned long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, int &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, int, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, unsigned int &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, unsigned int, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, long long &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, long long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, unsigned long long &value) + const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, unsigned long long, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, double &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, double, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, float &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, float, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, const char *&value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, const char *, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::lookupValue(const char *name, std::string &value) const throw() +{ + SETTING_LOOKUP_NO_EXCEPTIONS(name, const char *, value); +} + +// --------------------------------------------------------------------------- + +bool Setting::exists(const char *name) const throw() +{ + if(_type != TypeGroup) + return(false); + + config_setting_t *setting = config_setting_get_member(_setting, name); + + return(setting != NULL); +} + +// --------------------------------------------------------------------------- + +int Setting::getLength() const throw() +{ + return(config_setting_length(_setting)); +} + +// --------------------------------------------------------------------------- + +const char * Setting::getName() const throw() +{ + return(config_setting_name(_setting)); +} + +// --------------------------------------------------------------------------- + +std::string Setting::getPath() const +{ + std::stringstream path; + + __constructPath(*this, path); + + return(path.str()); +} + +// --------------------------------------------------------------------------- + +const Setting & Setting::getParent() const throw(SettingNotFoundException) +{ + config_setting_t *setting = config_setting_parent(_setting); + + if(! setting) + throw SettingNotFoundException(); + + return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::getParent() throw(SettingNotFoundException) +{ + config_setting_t *setting = config_setting_parent(_setting); + + if(! setting) + throw SettingNotFoundException(); + + return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +bool Setting::isRoot() const throw() +{ + return(config_setting_is_root(_setting)); +} + +// --------------------------------------------------------------------------- + +int Setting::getIndex() const throw() +{ + return(config_setting_index(_setting)); +} + +// --------------------------------------------------------------------------- + +void Setting::remove(const char *name) + throw(SettingTypeException, SettingNotFoundException) +{ + assertType(TypeGroup); + + if(! config_setting_remove(_setting, name)) + throw SettingNotFoundException(); +} + +// --------------------------------------------------------------------------- + +void Setting::remove(unsigned int idx) + throw(SettingTypeException, SettingNotFoundException) +{ + if((_type != TypeArray) && (_type != TypeGroup) && (_type != TypeList)) + throw SettingTypeException(); + + if(! config_setting_remove_elem(_setting, idx)) + throw SettingNotFoundException(); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::add(const char *name, Setting::Type type) + throw(SettingNameException, SettingTypeException) +{ + assertType(TypeGroup); + + int typecode = __toTypeCode(type); + + if(typecode == CONFIG_TYPE_NONE) + throw SettingTypeException(); + + config_setting_t *setting = config_setting_add(_setting, name, typecode); + + if(! setting) + throw SettingNameException(); + + return(wrapSetting(setting)); +} + +// --------------------------------------------------------------------------- + +Setting & Setting::add(Setting::Type type) throw(SettingTypeException) +{ + if((_type != TypeArray) && (_type != TypeList)) + throw SettingTypeException(); + + if(_type == TypeArray) + { + if(getLength() > 0) + { + Setting::Type atype = operator[](0).getType(); + if(type != atype) + throw SettingTypeException(); + } + else + { + if((type != TypeInt) && (type != TypeFloat) && (type != TypeString) + && (type != TypeBoolean)) + throw SettingTypeException(); + } + } + + int typecode = __toTypeCode(type); + config_setting_t *s = config_setting_add(_setting, NULL, typecode); + + Setting &ns = wrapSetting(s); + + switch(type) + { + case TypeInt: + ns = 0; + break; + + case TypeInt64: + ns = INT64_CONST(0); + break; + + case TypeFloat: + ns = 0.0; + break; + + case TypeString: + ns = (char *)NULL; + break; + + case TypeBoolean: + ns = false; + break; + + default: + // won't happen + break; + } + + return(ns); +} + +// --------------------------------------------------------------------------- + +void Setting::assertType(Setting::Type type) const throw(SettingTypeException) +{ + if(type != _type) + { + if(!(isNumber() && config_get_auto_convert(_setting->config) + && ((type == TypeInt) || (type == TypeFloat)))) + throw SettingTypeException(); + } +} + +// --------------------------------------------------------------------------- + +Setting & Setting::wrapSetting(config_setting_t *s) +{ + Setting *setting = NULL; + + void *hook = config_setting_get_hook(s); + if(! hook) + { + setting = new Setting(s); + config_setting_set_hook(s, reinterpret_cast(setting)); + } + else + setting = reinterpret_cast(hook); + + return(*setting); +} + +// --------------------------------------------------------------------------- +// eof Index: /tags/2.0-rc2/external/libconfig/private.h =================================================================== --- /tags/2.0-rc2/external/libconfig/private.h (revision 1304) +++ /tags/2.0-rc2/external/libconfig/private.h (revision 1304) @@ -0,0 +1,37 @@ +/* ---------------------------------------------------------------------------- + libconfig - A structured configuration file parsing library + Copyright (C) 2005 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_private_h +#define __libconfig_private_h + +#include "libconfig.h" + +struct parse_context +{ + config_t *config; + config_setting_t *parent; + config_setting_t *setting; + char *name; +}; + +// --------------------------------------------------------------------------- +#endif // __libconfig_private_h Index: /tags/2.0-rc2/external/libconfig/libconfig.h =================================================================== --- /tags/2.0-rc2/external/libconfig/libconfig.h (revision 1304) +++ /tags/2.0-rc2/external/libconfig/libconfig.h (revision 1304) @@ -0,0 +1,253 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2008 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_h +#define __libconfig_h + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(LIBCONFIG_STATIC) +#define LIBCONFIG_API +#elif defined(LIBCONFIG_EXPORTS) +#define LIBCONFIG_API __declspec(dllexport) +#else /* ! LIBCONFIG_EXPORTS */ +#define LIBCONFIG_API __declspec(dllimport) +#endif /* LIBCONFIG_STATIC */ +#else /* ! WIN32 */ +#define LIBCONFIG_API +#endif /* WIN32 */ + +#include + +#define CONFIG_TYPE_NONE 0 +#define CONFIG_TYPE_GROUP 1 +#define CONFIG_TYPE_INT 2 +#define CONFIG_TYPE_INT64 3 +#define CONFIG_TYPE_FLOAT 4 +#define CONFIG_TYPE_STRING 5 +#define CONFIG_TYPE_BOOL 6 +#define CONFIG_TYPE_ARRAY 7 +#define CONFIG_TYPE_LIST 8 + +#define CONFIG_FORMAT_DEFAULT 0 +#define CONFIG_FORMAT_HEX 1 + +#define CONFIG_OPTION_AUTOCONVERT 0x01 + +#define CONFIG_TRUE (1) +#define CONFIG_FALSE (0) + +typedef union config_value_t +{ + long ival; + long long llval; + double fval; + char *sval; + struct config_list_t *list; +} config_value_t; + +typedef struct config_setting_t +{ + char *name; + short type; + short format; + config_value_t value; + struct config_setting_t *parent; + struct config_t *config; + void *hook; + unsigned int line; +} config_setting_t; + +typedef struct config_list_t +{ + unsigned int length; + unsigned int capacity; + config_setting_t **elements; +} config_list_t; + +typedef struct config_t +{ + config_setting_t *root; + void (*destructor)(void *); + int flags; + const char *error_text; + int error_line; +} config_t; + +extern LIBCONFIG_API int config_read(config_t *config, FILE *stream); +extern LIBCONFIG_API void config_write(const config_t *config, FILE *stream); + +extern LIBCONFIG_API void config_set_auto_convert(config_t *config, int flag); +extern LIBCONFIG_API int config_get_auto_convert(const config_t *config); + +extern LIBCONFIG_API int config_read_file(config_t *config, + const char *filename); +extern LIBCONFIG_API int config_write_file(config_t *config, + const char *filename); + +extern LIBCONFIG_API void config_set_destructor(config_t *config, + void (*destructor)(void *)); + +extern LIBCONFIG_API void config_init(config_t *config); +extern LIBCONFIG_API void config_destroy(config_t *config); + +extern LIBCONFIG_API long config_setting_get_int( + const config_setting_t *setting); +extern LIBCONFIG_API long long config_setting_get_int64( + const config_setting_t *setting); +extern LIBCONFIG_API double config_setting_get_float( + const config_setting_t *setting); +extern LIBCONFIG_API int config_setting_get_bool( + const config_setting_t *setting); +extern LIBCONFIG_API const char *config_setting_get_string( + const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_set_int(config_setting_t *setting, + long value); +extern LIBCONFIG_API int config_setting_set_int64(config_setting_t *setting, + long long value); +extern LIBCONFIG_API int config_setting_set_float(config_setting_t *setting, + double value); +extern LIBCONFIG_API int config_setting_set_bool(config_setting_t *setting, + int value); +extern LIBCONFIG_API int config_setting_set_string(config_setting_t *setting, + const char *value); + +extern LIBCONFIG_API int config_setting_set_format(config_setting_t *setting, + short format); +extern LIBCONFIG_API short config_setting_get_format(config_setting_t *setting); + +extern LIBCONFIG_API long config_setting_get_int_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API long long config_setting_get_int64_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API double config_setting_get_float_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API int config_setting_get_bool_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API const char *config_setting_get_string_elem( + const config_setting_t *setting, int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_set_int_elem( + config_setting_t *setting, int idx, long value); +extern LIBCONFIG_API config_setting_t *config_setting_set_int64_elem( + config_setting_t *setting, int idx, long long value); +extern LIBCONFIG_API config_setting_t *config_setting_set_float_elem( + config_setting_t *setting, int idx, double value); +extern LIBCONFIG_API config_setting_t *config_setting_set_bool_elem( + config_setting_t *setting, int idx, int value); +extern LIBCONFIG_API config_setting_t *config_setting_set_string_elem( + config_setting_t *setting, int idx, const char *value); + +#define /* int */ config_setting_type(/* const config_setting_t * */ S) \ + ((S)->type) + +#define /* int */ config_setting_is_group(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_GROUP) +#define /* int */ config_setting_is_array(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_ARRAY) +#define /* int */ config_setting_is_list(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_LIST) + +#define /* int */ config_setting_is_aggregate( \ + /* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_GROUP) || ((S)->type == CONFIG_TYPE_LIST) \ + || ((S)->type == CONFIG_TYPE_ARRAY)) + +#define /* int */ config_setting_is_number(/* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_INT) \ + || ((S)->type == CONFIG_TYPE_INT64) \ + || ((S)->type == CONFIG_TYPE_FLOAT)) + +#define /* int */ config_setting_is_scalar(/* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_BOOL) || ((S)->type == CONFIG_TYPE_STRING) \ + || config_setting_is_number(S)) + +#define /* const char * */ config_setting_name( \ + /* const config_setting_t * */ S) \ + ((S)->name) + +#define /* config_setting_t * */ config_setting_parent( \ + /* const config_setting_t * */ S) \ + ((S)->parent) + +#define /* int */ config_setting_is_root( \ + /* const config_setting_t * */ S) \ + ((S)->parent ? CONFIG_FALSE : CONFIG_TRUE) + +extern LIBCONFIG_API int config_setting_index(const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_length( + const config_setting_t *setting); +extern LIBCONFIG_API config_setting_t *config_setting_get_elem( + const config_setting_t *setting, unsigned int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_get_member( + const config_setting_t *setting, const char *name); + +extern LIBCONFIG_API config_setting_t *config_setting_add( + config_setting_t *parent, const char *name, int type); +extern LIBCONFIG_API int config_setting_remove(config_setting_t *parent, + const char *name); +extern LIBCONFIG_API int config_setting_remove_elem(config_setting_t *parent, + unsigned int idx); +extern LIBCONFIG_API void config_setting_set_hook(config_setting_t *setting, + void *hook); + +#define config_setting_get_hook(S) ((S)->hook) + +extern LIBCONFIG_API config_setting_t *config_lookup(const config_t *config, + const char *path); + +extern LIBCONFIG_API long config_lookup_int(const config_t *config, + const char *path); +extern LIBCONFIG_API long long config_lookup_int64(const config_t *config, + const char *path); +extern LIBCONFIG_API double config_lookup_float(const config_t *config, + const char *path); +extern LIBCONFIG_API int config_lookup_bool(const config_t *config, + const char *path); +extern LIBCONFIG_API const char *config_lookup_string(const config_t *config, + const char *path); + +#define /* config_setting_t * */ config_root_setting( \ + /* const config_t * */ C) \ + ((C)->root) + +#define /* unsigned short */ config_setting_source_line( \ + /* const config_t */ C) \ + ((C)->line) + +#define /* const char * */ config_error_text(/* const config_t * */ C) \ + ((C)->error_text) + +#define /* int */ config_error_line(/* const config_t * */ C) \ + ((C)->error_line) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __libconfig_h */ Index: /tags/2.0-rc2/external/libconfig/libconfigpp.h =================================================================== --- /tags/2.0-rc2/external/libconfig/libconfigpp.h (revision 1304) +++ /tags/2.0-rc2/external/libconfig/libconfigpp.h (revision 1304) @@ -0,0 +1,383 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2008 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_hpp +#define __libconfig_hpp + +#include +#include +#include + +namespace libconfig +{ + +#include "libconfig.h" + + class LIBCONFIG_API ConfigException { }; + + class LIBCONFIG_API SettingException : public ConfigException + { + public: + + SettingException(); + virtual ~SettingException(); + }; + + class LIBCONFIG_API SettingTypeException : public SettingException + { + public: + + SettingTypeException(); + }; + + class LIBCONFIG_API SettingNotFoundException : public SettingException + { + public: + + SettingNotFoundException(); + }; + + class LIBCONFIG_API SettingNameException : public SettingException + { + public: + + SettingNameException(); + }; + + class LIBCONFIG_API FileIOException : public ConfigException { }; + + class LIBCONFIG_API ParseException : public ConfigException + { + friend class Config; + + public: + + virtual ~ParseException(); + + inline int getLine() throw() + { return(_line); } + + inline const char *getError() throw() + { return(_error); } + + private: + + ParseException(int line, const char *error); + + int _line; + const char *_error; + }; + + class LIBCONFIG_API Setting + { + friend class Config; + + public: + + enum Type + { + TypeNone = 0, + // scalar types + TypeInt, + TypeInt64, + TypeFloat, + TypeString, + TypeBoolean, + // aggregate types + TypeGroup, + TypeArray, + TypeList + }; + + enum Format + { + FormatDefault = 0, + FormatHex = 1 + }; + + private: + + config_setting_t *_setting; + Type _type; + Format _format; + + Setting(config_setting_t *setting); + + void assertType(Type type) const + throw(SettingTypeException); + static Setting & wrapSetting(config_setting_t *setting); + + Setting(const Setting& other); // not supported + Setting& operator=(const Setting& other); // not supported + + public: + + virtual ~Setting() throw(); + + inline Type getType() const throw() { return(_type); } + + inline Format getFormat() const throw() { return(_format); } + void setFormat(Format format) throw(); + + operator bool() const throw(SettingTypeException); + operator long() const throw(SettingTypeException); + operator unsigned long() const throw(SettingTypeException); + operator int() const throw(SettingTypeException); + operator unsigned int() const throw(SettingTypeException); + operator long long() const throw(SettingTypeException); + operator unsigned long long() const throw(SettingTypeException); + operator double() const throw(SettingTypeException); + operator float() const throw(SettingTypeException); + operator const char *() const throw(SettingTypeException); + operator std::string() const throw(SettingTypeException); + + Setting & operator=(bool value) throw(SettingTypeException); + Setting & operator=(long value) throw(SettingTypeException); + Setting & operator=(int value) throw(SettingTypeException); + Setting & operator=(const long long &value) throw(SettingTypeException); + Setting & operator=(const double &value) throw(SettingTypeException); + Setting & operator=(float value) throw(SettingTypeException); + Setting & operator=(const char *value) throw(SettingTypeException); + Setting & operator=(const std::string &value) throw(SettingTypeException); + + Setting & operator[](const char * key) const + throw(SettingTypeException, SettingNotFoundException); + + inline Setting & operator[](const std::string & key) const + throw(SettingTypeException, SettingNotFoundException) + { return(operator[](key.c_str())); } + + Setting & operator[](int index) const + throw(SettingTypeException, SettingNotFoundException); + + bool lookupValue(const char *name, bool &value) const throw(); + bool lookupValue(const char *name, long &value) const throw(); + bool lookupValue(const char *name, unsigned long &value) const throw(); + bool lookupValue(const char *name, int &value) const throw(); + bool lookupValue(const char *name, unsigned int &value) const throw(); + bool lookupValue(const char *name, long long &value) const throw(); + bool lookupValue(const char *name, unsigned long long &value) + const throw(); + bool lookupValue(const char *name, double &value) const throw(); + bool lookupValue(const char *name, float &value) const throw(); + bool lookupValue(const char *name, const char *&value) const throw(); + bool lookupValue(const char *name, std::string &value) const throw(); + + inline bool lookupValue(const std::string &name, bool &value) + const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, long &value) + const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, unsigned long &value) + const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, int &value) const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, unsigned int &value) + const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, long long &value) + const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, + unsigned long long &value) const throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, double &value) const + throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, float &value) const + throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, const char *&value) const + throw() + { return(lookupValue(name.c_str(), value)); } + + inline bool lookupValue(const std::string &name, std::string &value) const + throw() + { return(lookupValue(name.c_str(), value)); } + + void remove(const char *name) + throw(SettingTypeException, SettingNotFoundException); + + inline void remove(const std::string & name) + throw(SettingTypeException, SettingNotFoundException) + { remove(name.c_str()); } + + void remove(unsigned int idx) + throw(SettingTypeException, SettingNotFoundException); + + inline Setting & add(const std::string & name, Type type) + throw(SettingNameException, SettingTypeException) + { return(add(name.c_str(), type)); } + + Setting & add(const char *name, Type type) + throw(SettingNameException, SettingTypeException); + + Setting & add(Type type) + throw(SettingTypeException); + + inline bool exists(const std::string & name) const throw() + { return(exists(name.c_str())); } + + bool exists(const char *name) const throw(); + + int getLength() const throw(); + const char *getName() const throw(); + std::string getPath() const; + int getIndex() const throw(); + + const Setting & getParent() const throw(SettingNotFoundException); + Setting & getParent() throw(SettingNotFoundException); + + bool isRoot() const throw(); + + inline bool isGroup() const throw() + { return(_type == TypeGroup); } + + inline bool isArray() const throw() + { return(_type == TypeArray); } + + inline bool isList() const throw() + { return(_type == TypeList); } + + inline bool isAggregate() const throw() + { return(_type >= TypeGroup); } + + inline bool isScalar() const throw() + { return((_type > TypeNone) && (_type < TypeGroup)); } + + inline bool isNumber() const throw() + { return((_type == TypeInt) || (_type == TypeInt64) + || (_type == TypeFloat)); } + + inline unsigned int getSourceLine() const throw() + { return(config_setting_source_line(_setting)); } + }; + + class LIBCONFIG_API Config + { + private: + + config_t _config; + + static void ConfigDestructor(void *arg); + Config(const Config& other); // not supported + Config& operator=(const Config& other); // not supported + + public: + + Config(); + virtual ~Config(); + + void setAutoConvert(bool flag); + bool getAutoConvert() const; + + void read(FILE *stream) throw(ParseException); + void write(FILE *stream) const; + + void readFile(const char *filename) throw(FileIOException, ParseException); + void writeFile(const char *filename) throw(FileIOException); + + inline Setting & lookup(const std::string &path) const + throw(SettingNotFoundException) + { return(lookup(path.c_str())); } + + Setting & lookup(const char *path) const + throw(SettingNotFoundException); + + inline bool exists(const std::string & path) const throw() + { return(exists(path.c_str())); } + + bool exists(const char *path) const throw(); + + bool lookupValue(const char *path, bool &value) const throw(); + bool lookupValue(const char *path, long &value) const throw(); + bool lookupValue(const char *path, unsigned long &value) const throw(); + bool lookupValue(const char *path, int &value) const throw(); + bool lookupValue(const char *path, unsigned int &value) const throw(); + bool lookupValue(const char *path, long long &value) const throw(); + bool lookupValue(const char *path, unsigned long long &value) + const throw(); + bool lookupValue(const char *path, double &value) const throw(); + bool lookupValue(const char *path, float &value) const throw(); + bool lookupValue(const char *path, const char *&value) const throw(); + bool lookupValue(const char *path, std::string &value) const throw(); + + inline bool lookupValue(const std::string &path, bool &value) + const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, long &value) + const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, unsigned long &value) + const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, int &value) const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, unsigned int &value) + const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, long long &value) + const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, + unsigned long long &value) const throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, double &value) const + throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, float &value) const + throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, const char *&value) const + throw() + { return(lookupValue(path.c_str(), value)); } + + inline bool lookupValue(const std::string &path, std::string &value) const + throw() + { return(lookupValue(path.c_str(), value)); } + + Setting & getRoot() const; + }; + +} // namespace libconfig + +#endif // __libconfig_hpp Index: /tags/2.0-rc2/external/libconfig/SConscript =================================================================== --- /tags/2.0-rc2/external/libconfig/SConscript (revision 1478) +++ /tags/2.0-rc2/external/libconfig/SConscript (revision 1478) @@ -0,0 +1,41 @@ +# +# Copyright (C) 2007 Arnold Krille +# Copyright (C) 2007 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 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 . +# + +Import( 'env' ) +env = env.Clone() + +env.AppendUnique( CPPPATH=["#/external/libconfig"] ) + +sources = [ + 'grammar.c', + 'libconfig.c', + 'libconfigcpp.cpp', + 'scanner.c', +] + +if env.has_key('DEBUG') and env['DEBUG']: + env.AppendUnique( CCFLAGS=["-DDEBUG","-g"] ) + +env.AppendUnique( CCFLAGS=["-DYY_NO_INPUT"] ) + +libconfig = env.StaticLibrary('libconfigpp', sources) Index: /tags/2.0-rc2/external/libconfig/grammar.c =================================================================== --- /tags/2.0-rc2/external/libconfig/grammar.c (revision 1304) +++ /tags/2.0-rc2/external/libconfig/grammar.c (revision 1304) @@ -0,0 +1,1928 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + 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, 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. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse libconfig_yyparse +#define yylex libconfig_yylex +#define yyerror libconfig_yyerror +#define yylval libconfig_yylval +#define yychar libconfig_yychar +#define yydebug libconfig_yydebug +#define yynerrs libconfig_yynerrs + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TOK_BOOLEAN = 258, + TOK_INTEGER = 259, + TOK_HEX = 260, + TOK_INTEGER64 = 261, + TOK_HEX64 = 262, + TOK_FLOAT = 263, + TOK_STRING = 264, + TOK_NAME = 265, + TOK_EQUALS = 266, + TOK_NEWLINE = 267, + TOK_ARRAY_START = 268, + TOK_ARRAY_END = 269, + TOK_LIST_START = 270, + TOK_LIST_END = 271, + TOK_COMMA = 272, + TOK_GROUP_START = 273, + TOK_GROUP_END = 274, + TOK_END = 275, + TOK_GARBAGE = 276 + }; +#endif +/* Tokens. */ +#define TOK_BOOLEAN 258 +#define TOK_INTEGER 259 +#define TOK_HEX 260 +#define TOK_INTEGER64 261 +#define TOK_HEX64 262 +#define TOK_FLOAT 263 +#define TOK_STRING 264 +#define TOK_NAME 265 +#define TOK_EQUALS 266 +#define TOK_NEWLINE 267 +#define TOK_ARRAY_START 268 +#define TOK_ARRAY_END 269 +#define TOK_LIST_START 270 +#define TOK_LIST_END 271 +#define TOK_COMMA 272 +#define TOK_GROUP_START 273 +#define TOK_GROUP_END 274 +#define TOK_END 275 +#define TOK_GARBAGE 276 + + + + +/* Copy the first part of user declarations. */ +#line 31 "grammar.y" + +#include +#include +#include "libconfig.h" +#ifdef WIN32 +#include "wincompat.h" + +/* prevent warnings about redefined malloc/free in generated code: */ +#ifndef _STDLIB_H +#define _STDLIB_H +#endif + +#include +#endif +#include "private.h" + +/* these delcarations are provided to suppress compiler warnings */ +extern int libconfig_yylex(); +extern int libconfig_yyget_lineno(); + +static const char *err_array_elem_type = "mismatched element type in array"; +static const char *err_duplicate_setting = "duplicate setting name"; + +#define IN_ARRAY() \ + (ctx->parent && (ctx->parent->type == CONFIG_TYPE_ARRAY)) + +#define IN_LIST() \ + (ctx->parent && (ctx->parent->type == CONFIG_TYPE_LIST)) + +#define CAPTURE_PARSE_POS(S) \ + (S)->line = (unsigned int)libconfig_yyget_lineno(scanner) + +void libconfig_yyerror(void *scanner, struct parse_context *ctx, + char const *s) +{ + ctx->config->error_line = libconfig_yyget_lineno(scanner); + ctx->config->error_text = s; +} + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 73 "grammar.y" +{ + long ival; + long long llval; + double fval; + char *sval; +} +/* Line 187 of yacc.c. */ +#line 194 "grammar.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 207 "grammar.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 6 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 32 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 22 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 18 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 34 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 43 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 276 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 4, 6, 8, 11, 12, 14, 15, + 21, 22, 27, 28, 33, 35, 37, 39, 41, 43, + 45, 47, 49, 51, 53, 55, 57, 61, 62, 64, + 66, 70, 71, 73, 74 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 23, 0, -1, -1, 24, -1, 26, -1, 24, 26, + -1, -1, 24, -1, -1, 10, 27, 11, 32, 20, + -1, -1, 13, 29, 37, 14, -1, -1, 15, 31, + 35, 16, -1, 33, -1, 28, -1, 30, -1, 38, + -1, 3, -1, 4, -1, 6, -1, 5, -1, 7, + -1, 8, -1, 9, -1, 32, -1, 34, 17, 32, + -1, -1, 34, -1, 33, -1, 36, 17, 33, -1, + -1, 36, -1, -1, 18, 39, 25, 19, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 88, 88, 90, 94, 95, 98, 100, 105, 104, + 125, 124, 148, 147, 170, 171, 172, 173, 177, 197, + 219, 241, 263, 285, 303, 330, 331, 334, 336, 340, + 341, 344, 346, 351, 350 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "TOK_BOOLEAN", "TOK_INTEGER", "TOK_HEX", + "TOK_INTEGER64", "TOK_HEX64", "TOK_FLOAT", "TOK_STRING", "TOK_NAME", + "TOK_EQUALS", "TOK_NEWLINE", "TOK_ARRAY_START", "TOK_ARRAY_END", + "TOK_LIST_START", "TOK_LIST_END", "TOK_COMMA", "TOK_GROUP_START", + "TOK_GROUP_END", "TOK_END", "TOK_GARBAGE", "$accept", "configuration", + "setting_list", "setting_list_optional", "setting", "@1", "array", "@2", + "list", "@3", "value", "simple_value", "value_list", + "value_list_optional", "simple_value_list", "simple_value_list_optional", + "group", "@4", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 22, 23, 23, 24, 24, 25, 25, 27, 26, + 29, 28, 31, 30, 32, 32, 32, 32, 33, 33, + 33, 33, 33, 33, 33, 34, 34, 35, 35, 36, + 36, 37, 37, 39, 38 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 1, 1, 2, 0, 1, 0, 5, + 0, 4, 0, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 0, 1, 1, + 3, 0, 1, 0, 4 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 8, 0, 3, 4, 0, 1, 5, 0, 18, + 19, 21, 20, 22, 23, 24, 10, 12, 33, 15, + 16, 0, 14, 17, 31, 27, 6, 9, 29, 32, + 0, 25, 28, 0, 7, 0, 0, 11, 0, 13, + 34, 30, 26 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 2, 3, 35, 4, 5, 19, 24, 20, 25, + 21, 22, 32, 33, 29, 30, 23, 26 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -18 +static const yytype_int8 yypact[] = +{ + -1, -18, 12, -1, -18, 3, -18, -18, -2, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -5, -18, -18, 20, -2, -1, -18, -18, 0, + 4, -18, 2, 14, -1, 1, 20, -18, -2, -18, + -18, -18, -18 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -18, -18, 6, -18, -3, -18, -18, -18, -18, -18, + -17, -14, -18, -18, -18, -18, -18, -18 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 7, 9, 10, 11, 12, 13, 14, 15, 31, 1, + 28, 16, 6, 17, 8, 27, 18, 36, 37, 38, + 40, 42, 41, 9, 10, 11, 12, 13, 14, 15, + 39, 7, 34 +}; + +static const yytype_uint8 yycheck[] = +{ + 3, 3, 4, 5, 6, 7, 8, 9, 25, 10, + 24, 13, 0, 15, 11, 20, 18, 17, 14, 17, + 19, 38, 36, 3, 4, 5, 6, 7, 8, 9, + 16, 34, 26 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 10, 23, 24, 26, 27, 0, 26, 11, 3, + 4, 5, 6, 7, 8, 9, 13, 15, 18, 28, + 30, 32, 33, 38, 29, 31, 39, 20, 33, 36, + 37, 32, 34, 35, 24, 25, 17, 14, 17, 16, + 19, 33, 32 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (scanner, ctx, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, scanner, ctx); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + void *scanner; + struct parse_context *ctx; +#endif +{ + if (!yyvaluep) + return; + YYUSE (scanner); + YYUSE (ctx); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, scanner, ctx) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + void *scanner; + struct parse_context *ctx; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule, void *scanner, struct parse_context *ctx) +#else +static void +yy_reduce_print (yyvsp, yyrule, scanner, ctx) + YYSTYPE *yyvsp; + int yyrule; + void *scanner; + struct parse_context *ctx; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , scanner, ctx); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule, scanner, ctx); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *scanner, struct parse_context *ctx) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, scanner, ctx) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + void *scanner; + struct parse_context *ctx; +#endif +{ + YYUSE (yyvaluep); + YYUSE (scanner); + YYUSE (ctx); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void *scanner, struct parse_context *ctx); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *scanner, struct parse_context *ctx) +#else +int +yyparse (scanner, ctx) + void *scanner; + struct parse_context *ctx; +#endif +#endif +{ + /* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 8: +#line 105 "grammar.y" + { + ctx->setting = config_setting_add(ctx->parent, (yyvsp[(1) - (1)].sval), CONFIG_TYPE_NONE); + free((yyvsp[(1) - (1)].sval)); + + if(ctx->setting == NULL) + { + libconfig_yyerror(scanner, ctx, err_duplicate_setting); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(ctx->setting); + } + } + break; + + case 10: +#line 125 "grammar.y" + { + if(IN_LIST()) + { + ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_ARRAY); + CAPTURE_PARSE_POS(ctx->parent); + } + else + { + ctx->setting->type = CONFIG_TYPE_ARRAY; + ctx->parent = ctx->setting; + ctx->setting = NULL; + } + } + break; + + case 11: +#line 140 "grammar.y" + { + if(ctx->parent) + ctx->parent = ctx->parent->parent; + } + break; + + case 12: +#line 148 "grammar.y" + { + if(IN_LIST()) + { + ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_LIST); + CAPTURE_PARSE_POS(ctx->parent); + } + else + { + ctx->setting->type = CONFIG_TYPE_LIST; + ctx->parent = ctx->setting; + ctx->setting = NULL; + } + } + break; + + case 13: +#line 163 "grammar.y" + { + if(ctx->parent) + ctx->parent = ctx->parent->parent; + } + break; + + case 18: +#line 178 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_bool_elem(ctx->parent, -1, + (int)(yyvsp[(1) - (1)].ival)); + + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(e); + } + } + else + config_setting_set_bool(ctx->setting, (int)(yyvsp[(1) - (1)].ival)); + } + break; + + case 19: +#line 198 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival)); + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_DEFAULT); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT); + } + } + break; + + case 20: +#line 220 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval)); + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_DEFAULT); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT); + } + } + break; + + case 21: +#line 242 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival)); + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_HEX); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX); + } + } + break; + + case 22: +#line 264 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval)); + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_HEX); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX); + } + } + break; + + case 23: +#line 286 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_float_elem(ctx->parent, -1, (yyvsp[(1) - (1)].fval)); + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(e); + } + } + else + config_setting_set_float(ctx->setting, (yyvsp[(1) - (1)].fval)); + } + break; + + case 24: +#line 304 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_string_elem(ctx->parent, -1, + (yyvsp[(1) - (1)].sval)); + free((yyvsp[(1) - (1)].sval)); + + if(! e) + { + libconfig_yyerror(scanner, ctx, err_array_elem_type); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_string(ctx->setting, (yyvsp[(1) - (1)].sval)); + free((yyvsp[(1) - (1)].sval)); + } + } + break; + + case 33: +#line 351 "grammar.y" + { + if(IN_LIST()) + { + ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_GROUP); + CAPTURE_PARSE_POS(ctx->parent); + } + else + { + ctx->setting->type = CONFIG_TYPE_GROUP; + ctx->parent = ctx->setting; + ctx->setting = NULL; + } + } + break; + + case 34: +#line 366 "grammar.y" + { + if(ctx->parent) + ctx->parent = ctx->parent->parent; + } + break; + + +/* Line 1267 of yacc.c. */ +#line 1713 "grammar.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (scanner, ctx, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (scanner, ctx, yymsg); + } + else + { + yyerror (scanner, ctx, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, scanner, ctx); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, scanner, ctx); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (scanner, ctx, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, scanner, ctx); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, scanner, ctx); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 372 "grammar.y" + + Index: /tags/2.0-rc2/external/libconfig/wincompat.h =================================================================== --- /tags/2.0-rc2/external/libconfig/wincompat.h (revision 1304) +++ /tags/2.0-rc2/external/libconfig/wincompat.h (revision 1304) @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2008 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ + +#ifndef __wincompat_h +#define __wincompat_h + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + +#include + +#define atoll _atoi64 +#define strtoull _strtoui64 +#define snprintf _snprintf + +#endif + +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ + && ! defined(__MINGW32__) + +#define INT64_FMT "%I64d" +#define UINT64_FMT "%I64u" + +#define INT64_HEX_FMT "%I64X" + +#define INT64_CONST(I) (I ## i64) +#define UINT64_CONST(I) (I ## Ui64) + +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif + +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif + +#else // defined(WIN32) && ! defined(__MINGW32__) + +#define INT64_FMT "%lld" +#define UINT64_FMT "%llu" + +#define INT64_HEX_FMT "%llX" + +#define INT64_CONST(I) (I ## LL) +#define UINT64_CONST(I) (I ## ULL) + +#endif // defined(WIN32) && ! defined(__MINGW32__) + +#endif // __wincompat_h Index: /tags/2.0-rc2/external/libconfig/scanner.c =================================================================== --- /tags/2.0-rc2/external/libconfig/scanner.c (revision 1304) +++ /tags/2.0-rc2/external/libconfig/scanner.c (revision 1304) @@ -0,0 +1,2284 @@ +#line 2 "scanner.c" + +#line 4 "scanner.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 33 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +int libconfig_yylex_init (yyscan_t* scanner); + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE libconfig_yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE libconfig_yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via libconfig_yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void libconfig_yypop_buffer_state (yyscan_t yyscanner ); + +static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner ); +static void libconfig_yy_load_buffer_state (yyscan_t yyscanner ); +static void libconfig_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER libconfig_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void libconfig_yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer libconfig_yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + libconfig_yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + libconfig_yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +#define libconfig_yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 26 +#define YY_END_OF_BUFFER 27 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[117] = + { 0, + 0, 0, 0, 0, 27, 25, 5, 5, 25, 25, + 21, 22, 12, 25, 7, 13, 25, 14, 14, 6, + 23, 12, 12, 19, 20, 8, 9, 3, 4, 3, + 5, 0, 18, 0, 0, 24, 12, 13, 14, 13, + 0, 1, 0, 13, 0, 15, 0, 12, 12, 2, + 0, 0, 0, 0, 0, 13, 13, 0, 0, 13, + 15, 16, 12, 12, 0, 18, 0, 0, 0, 0, + 0, 13, 17, 12, 10, 0, 0, 17, 11, 0, + 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, + + 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, + 0, 18, 0, 0, 0, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 1, 1, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 17, 1, + 18, 1, 1, 1, 19, 20, 20, 20, 21, 22, + 23, 23, 23, 23, 23, 24, 23, 23, 23, 23, + 23, 25, 26, 27, 28, 23, 23, 29, 23, 23, + 30, 31, 32, 1, 33, 1, 19, 20, 20, 20, + + 21, 22, 23, 23, 23, 23, 23, 34, 23, 23, + 23, 23, 23, 25, 26, 27, 28, 23, 23, 29, + 23, 23, 35, 1, 36, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[37] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, + 2, 1, 1, 3, 3, 1, 1, 1, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, + 1, 1, 2, 2, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[128] = + { 0, + 0, 0, 34, 35, 199, 503, 37, 42, 37, 195, + 503, 503, 0, 34, 503, 36, 39, 57, 41, 503, + 503, 163, 150, 503, 503, 503, 503, 503, 503, 152, + 56, 56, 71, 160, 151, 503, 0, 49, 68, 76, + 84, 503, 150, 86, 94, 128, 0, 43, 118, 503, + 108, 57, 125, 106, 101, 103, 108, 116, 118, 120, + 503, 102, 98, 99, 75, 134, 101, 99, 138, 88, + 130, 134, 70, 64, 0, 58, 142, 503, 0, 154, + 166, 156, 158, 164, 172, 202, 177, 170, 180, 181, + 178, 214, 244, 256, 286, 189, 220, 316, 328, 192, + + 206, 218, 231, 340, 262, 222, 264, 229, 352, 382, + 412, 442, 270, 294, 358, 503, 473, 476, 479, 481, + 51, 484, 487, 490, 493, 496, 499 + } ; + +static yyconst flex_int16_t yy_def[128] = + { 0, + 116, 1, 117, 117, 116, 116, 116, 116, 118, 119, + 116, 116, 120, 116, 116, 116, 116, 116, 116, 116, + 116, 120, 120, 116, 116, 116, 116, 116, 116, 116, + 116, 118, 116, 118, 119, 116, 120, 116, 116, 116, + 116, 116, 119, 116, 116, 116, 121, 120, 120, 116, + 116, 122, 123, 116, 116, 116, 116, 116, 116, 116, + 116, 121, 120, 120, 122, 116, 122, 123, 116, 124, + 116, 116, 116, 120, 120, 124, 124, 116, 120, 124, + 124, 125, 126, 124, 125, 124, 125, 125, 126, 126, + 124, 125, 126, 125, 125, 127, 125, 126, 124, 127, + + 126, 126, 127, 126, 127, 127, 125, 126, 127, 127, + 125, 127, 127, 127, 127, 0, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116 + } ; + +static yyconst flex_int16_t yy_nxt[540] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 14, 16, 17, 18, 19, 20, 21, 20, 13, 13, + 13, 22, 13, 13, 13, 13, 23, 13, 13, 24, + 6, 25, 6, 13, 26, 27, 29, 29, 31, 31, + 33, 30, 30, 31, 31, 38, 42, 39, 39, 40, + 40, 43, 44, 62, 39, 39, 41, 31, 31, 33, + 66, 45, 40, 40, 46, 77, 63, 34, 44, 41, + 39, 39, 51, 51, 52, 53, 63, 45, 66, 44, + 46, 39, 39, 54, 79, 47, 34, 67, 45, 40, + 40, 46, 55, 78, 55, 77, 41, 56, 56, 57, + + 57, 69, 59, 116, 59, 67, 58, 60, 60, 51, + 51, 52, 53, 70, 56, 56, 56, 56, 53, 75, + 54, 57, 57, 74, 71, 73, 71, 69, 58, 72, + 72, 60, 60, 60, 60, 51, 51, 52, 53, 51, + 51, 52, 53, 72, 72, 64, 54, 72, 72, 77, + 54, 61, 36, 36, 80, 81, 81, 82, 83, 86, + 80, 77, 116, 87, 50, 90, 84, 81, 81, 82, + 83, 91, 76, 77, 49, 86, 83, 87, 84, 87, + 86, 48, 80, 80, 87, 77, 88, 90, 90, 92, + 80, 92, 104, 93, 92, 104, 105, 36, 116, 105, + + 116, 116, 88, 81, 81, 82, 83, 88, 80, 77, + 116, 116, 116, 90, 84, 94, 94, 95, 96, 106, + 80, 87, 106, 86, 80, 108, 97, 107, 116, 105, + 101, 80, 96, 92, 104, 116, 90, 116, 105, 116, + 116, 93, 116, 116, 88, 98, 99, 100, 101, 116, + 88, 90, 116, 116, 116, 116, 102, 94, 94, 95, + 96, 106, 116, 87, 92, 104, 116, 86, 97, 105, + 116, 87, 92, 104, 109, 116, 92, 105, 116, 116, + 116, 116, 116, 116, 116, 116, 88, 94, 94, 95, + 96, 116, 106, 87, 88, 116, 92, 104, 97, 116, + + 106, 115, 116, 116, 116, 116, 113, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 88, 98, 99, 100, + 101, 116, 116, 90, 106, 116, 116, 116, 102, 81, + 81, 82, 83, 116, 116, 77, 116, 116, 116, 116, + 84, 98, 99, 100, 101, 116, 116, 90, 116, 116, + 116, 116, 102, 110, 111, 112, 113, 116, 116, 105, + 92, 104, 116, 116, 114, 105, 116, 116, 116, 116, + 109, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 106, 110, 111, 112, 113, 116, 106, 105, + 116, 116, 116, 116, 114, 116, 116, 116, 116, 116, + + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 106, 94, 94, 95, 96, 116, 116, 87, + 116, 116, 116, 116, 97, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 88, 110, 111, 112, 113, 116, 116, 105, + 116, 116, 116, 116, 114, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 106, 28, 28, 28, 32, 32, 32, 35, + 35, 35, 37, 37, 65, 65, 65, 68, 68, 68, + 76, 76, 76, 85, 85, 85, 89, 89, 89, 103, + + 103, 103, 5, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116 + } ; + +static yyconst flex_int16_t yy_chk[540] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 7, 7, + 9, 3, 4, 8, 8, 14, 17, 14, 14, 16, + 16, 17, 19, 121, 19, 19, 16, 31, 31, 32, + 52, 19, 38, 38, 19, 76, 48, 9, 18, 38, + 18, 18, 33, 33, 33, 33, 48, 18, 65, 39, + 18, 39, 39, 33, 74, 18, 32, 52, 39, 40, + 40, 39, 41, 73, 41, 70, 40, 41, 41, 44, + + 44, 68, 45, 67, 45, 65, 44, 45, 45, 51, + 51, 51, 51, 54, 55, 55, 56, 56, 54, 64, + 51, 57, 57, 63, 58, 62, 58, 53, 57, 58, + 58, 59, 59, 60, 60, 66, 66, 66, 66, 69, + 69, 69, 69, 71, 71, 49, 66, 72, 72, 77, + 69, 46, 43, 35, 77, 80, 80, 80, 80, 82, + 83, 80, 34, 82, 30, 83, 80, 81, 81, 81, + 81, 84, 88, 81, 23, 85, 84, 88, 81, 85, + 87, 22, 89, 90, 87, 91, 82, 89, 90, 87, + 91, 96, 96, 90, 100, 100, 96, 10, 5, 100, + + 0, 0, 85, 86, 86, 86, 86, 87, 101, 86, + 0, 0, 0, 101, 86, 92, 92, 92, 92, 96, + 102, 92, 100, 97, 106, 102, 92, 97, 0, 106, + 102, 108, 97, 103, 103, 0, 108, 0, 103, 0, + 0, 108, 0, 0, 92, 93, 93, 93, 93, 0, + 97, 93, 0, 0, 0, 0, 93, 94, 94, 94, + 94, 103, 0, 94, 105, 105, 0, 107, 94, 105, + 0, 107, 113, 113, 105, 0, 107, 113, 0, 0, + 0, 0, 0, 0, 0, 0, 94, 95, 95, 95, + 95, 0, 105, 95, 107, 0, 114, 114, 95, 0, + + 113, 114, 0, 0, 0, 0, 114, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 95, 98, 98, 98, + 98, 0, 0, 98, 114, 0, 0, 0, 98, 99, + 99, 99, 99, 0, 0, 99, 0, 0, 0, 0, + 99, 104, 104, 104, 104, 0, 0, 104, 0, 0, + 0, 0, 104, 109, 109, 109, 109, 0, 0, 109, + 115, 115, 0, 0, 109, 115, 0, 0, 0, 0, + 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 110, 110, 110, 110, 0, 115, 110, + 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 110, 111, 111, 111, 111, 0, 0, 111, + 0, 0, 0, 0, 111, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 111, 112, 112, 112, 112, 0, 0, 112, + 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 112, 117, 117, 117, 118, 118, 118, 119, + 119, 119, 120, 120, 122, 122, 122, 123, 123, 123, + 124, 124, 124, 125, 125, 125, 126, 126, 126, 127, + + 127, 127, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[27] = + { 0, +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "scanner.l" +/* -*- mode: C -*- */ +/* -------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2008 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ +#line 25 "scanner.l" +#define YY_EXTRA_TYPE void* +#define YY_NO_UNISTD_H 1 +#line 38 "scanner.l" + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include +#include +#include "grammar.h" +#include "wincompat.h" + +/* this is somewhat kludgy, but I wanted to avoid building strings + dynamically during scanning */ + +static char *make_string(char *s) +{ + char *r = ++s; + char *p, *q = r; + size_t len = strlen(r); + int esc = 0; + + *(r + --len) = 0; + + for(p = r; *p; p++) + { + if(*p == '\\') + { + if(! esc) + { + esc = 1; + continue; + } + } + + if(esc) + { + if(*p == 'n') + *(q++) = '\n'; + else if(*p == 'r') + *(q++) = '\r'; + else if(*p == 'f') + *(q++) = '\f'; + else if(*p == 't') + *(q++) = '\t'; + else + *(q++) = *p; + + esc = 0; + } + + else if(*p == '\"') /* if we reached the end of a string segment, ... */ + { + /* This construction allows for C-style string concatenation. + We don't bother to check for end-of-string here, as we depend + on the {string} definition to ensure a new opening quote exists. + We do, however, check for and discard all forms of comments + [that is, (#...$|//...$|[/][*]...[*][/])] between string segments. */ + + while (*++p != '\"') /* ... look for the start of the next segment */ + { + if(*p == '#') /* check for #...$ comment */ + { + while(*++p != '\n') + { + /* skip the rest of the line */ + } + } + else if (*p == '/') + { + if(*++p == '/') /* check for //...$ comment */ + { + while (*++p != '\n') + { + /* skip the rest of the line */ + } + } + else /* must be '*', lead-in to an old C-style comment */ + { + while (*++p != '*' || *(p+1) != '/') + { + /* skip all comment content */ + } + ++p; /* step to the trailing slash, to skip it as well */ + } + } + } + } + else + *(q++) = *p; + } + + *q = 0; + + return(r); +} + + +#line 734 "scanner.c" + +#define INITIAL 0 +#define COMMENT 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int libconfig_yylex_destroy (yyscan_t yyscanner ); + +int libconfig_yyget_debug (yyscan_t yyscanner ); + +void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner ); + +void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_in (yyscan_t yyscanner ); + +void libconfig_yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_out (yyscan_t yyscanner ); + +void libconfig_yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int libconfig_yyget_leng (yyscan_t yyscanner ); + +char *libconfig_yyget_text (yyscan_t yyscanner ); + +int libconfig_yyget_lineno (yyscan_t yyscanner ); + +void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner ); + +void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int libconfig_yywrap (yyscan_t yyscanner ); +#else +extern int libconfig_yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int libconfig_yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int libconfig_yylex (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 160 "scanner.l" + + +#line 963 "scanner.c" + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + libconfig_yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + libconfig_yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 117 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 503 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 162 "scanner.l" +{ BEGIN COMMENT; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 163 "scanner.l" +{ BEGIN INITIAL; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 164 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +#line 165 "scanner.l" +{ } + YY_BREAK +case 5: +/* rule 5 can match eol */ +YY_RULE_SETUP +#line 167 "scanner.l" +{ /* skip */ } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 169 "scanner.l" +{ return(TOK_EQUALS); } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 170 "scanner.l" +{ return(TOK_COMMA); } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 171 "scanner.l" +{ return(TOK_GROUP_START); } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 172 "scanner.l" +{ return(TOK_GROUP_END); } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 173 "scanner.l" +{ yylval->ival = 1; return(TOK_BOOLEAN); } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 174 "scanner.l" +{ yylval->ival = 0; return(TOK_BOOLEAN); } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 175 "scanner.l" +{ yylval->sval = strdup(yytext); return(TOK_NAME); } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 176 "scanner.l" +{ yylval->fval = atof(yytext); return(TOK_FLOAT); } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 177 "scanner.l" +{ yylval->ival = atoi(yytext); return(TOK_INTEGER); } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 178 "scanner.l" +{ yylval->llval = atoll(yytext); return(TOK_INTEGER64); } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 179 "scanner.l" +{ yylval->ival = strtoul(yytext, NULL, 16); return(TOK_HEX); } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 180 "scanner.l" +{ yylval->llval = strtoull(yytext, NULL, 16); return(TOK_HEX64); } + YY_BREAK +case 18: +/* rule 18 can match eol */ +YY_RULE_SETUP +#line 181 "scanner.l" +{ yylval->sval = strdup(make_string(yytext)); return(TOK_STRING); } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 182 "scanner.l" +{ return(TOK_ARRAY_START); } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 183 "scanner.l" +{ return(TOK_ARRAY_END); } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 184 "scanner.l" +{ return(TOK_LIST_START); } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 185 "scanner.l" +{ return(TOK_LIST_END); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 186 "scanner.l" +{ return(TOK_END); } + YY_BREAK +case 24: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 187 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 188 "scanner.l" +{ return(TOK_GARBAGE); } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 189 "scanner.l" +ECHO; + YY_BREAK +#line 1196 "scanner.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMENT): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * libconfig_yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( libconfig_yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of libconfig_yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + libconfig_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + libconfig_yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 117 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 117 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 116); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + libconfig_yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( libconfig_yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void libconfig_yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + libconfig_yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + libconfig_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + libconfig_yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * libconfig_yypop_buffer_state(); + * libconfig_yypush_buffer_state(new_buffer); + */ + libconfig_yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + libconfig_yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (libconfig_yywrap()) processing, but the only time this flag + * is looked at is after libconfig_yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void libconfig_yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE libconfig_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) libconfig_yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + libconfig_yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with libconfig_yy_create_buffer() + * @param yyscanner The scanner object. + */ + void libconfig_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + libconfig_yyfree((void *) b->yy_ch_buf ,yyscanner ); + + libconfig_yyfree((void *) b ,yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a libconfig_yyrestart() or at EOF. + */ + static void libconfig_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + libconfig_yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then libconfig_yy_init_buffer was _probably_ + * called from libconfig_yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void libconfig_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + libconfig_yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + libconfig_yyensure_buffer_stack(yyscanner); + + /* This block is copied from libconfig_yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from libconfig_yy_switch_to_buffer. */ + libconfig_yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void libconfig_yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + libconfig_yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE libconfig_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + libconfig_yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to libconfig_yylex() will + * scan from a @e copy of @a str. + * @param str a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * libconfig_yy_scan_bytes() instead. + */ +YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return libconfig_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to libconfig_yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) libconfig_yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = libconfig_yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in libconfig_yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int libconfig_yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int libconfig_yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *libconfig_yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *libconfig_yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int libconfig_yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *libconfig_yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void libconfig_yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "libconfig_yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void libconfig_yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "libconfig_yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see libconfig_yy_switch_to_buffer + */ +void libconfig_yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void libconfig_yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int libconfig_yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void libconfig_yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void libconfig_yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* libconfig_yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int libconfig_yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from libconfig_yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * libconfig_yylex_init() + */ + return 0; +} + +/* libconfig_yylex_destroy is for both reentrant and non-reentrant scanners. */ +int libconfig_yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + libconfig_yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + libconfig_yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + libconfig_yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * libconfig_yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + libconfig_yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *libconfig_yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *libconfig_yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void libconfig_yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see libconfig_yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 189 "scanner.l" Index: /tags/2.0-rc2/external/libconfig/grammar.h =================================================================== --- /tags/2.0-rc2/external/libconfig/grammar.h (revision 1304) +++ /tags/2.0-rc2/external/libconfig/grammar.h (revision 1304) @@ -0,0 +1,105 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + 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, 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. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TOK_BOOLEAN = 258, + TOK_INTEGER = 259, + TOK_HEX = 260, + TOK_INTEGER64 = 261, + TOK_HEX64 = 262, + TOK_FLOAT = 263, + TOK_STRING = 264, + TOK_NAME = 265, + TOK_EQUALS = 266, + TOK_NEWLINE = 267, + TOK_ARRAY_START = 268, + TOK_ARRAY_END = 269, + TOK_LIST_START = 270, + TOK_LIST_END = 271, + TOK_COMMA = 272, + TOK_GROUP_START = 273, + TOK_GROUP_END = 274, + TOK_END = 275, + TOK_GARBAGE = 276 + }; +#endif +/* Tokens. */ +#define TOK_BOOLEAN 258 +#define TOK_INTEGER 259 +#define TOK_HEX 260 +#define TOK_INTEGER64 261 +#define TOK_HEX64 262 +#define TOK_FLOAT 263 +#define TOK_STRING 264 +#define TOK_NAME 265 +#define TOK_EQUALS 266 +#define TOK_NEWLINE 267 +#define TOK_ARRAY_START 268 +#define TOK_ARRAY_END 269 +#define TOK_LIST_START 270 +#define TOK_LIST_END 271 +#define TOK_COMMA 272 +#define TOK_GROUP_START 273 +#define TOK_GROUP_END 274 +#define TOK_END 275 +#define TOK_GARBAGE 276 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 73 "grammar.y" +{ + long ival; + long long llval; + double fval; + char *sval; +} +/* Line 1489 of yacc.c. */ +#line 98 "grammar.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + Index: /tags/2.0-rc2/external/libconfig/libconfig.c =================================================================== --- /tags/2.0-rc2/external/libconfig/libconfig.c (revision 1304) +++ /tags/2.0-rc2/external/libconfig/libconfig.c (revision 1304) @@ -0,0 +1,1310 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2008 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + 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 Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include "libconfig.h" +#include "grammar.h" +#include "scanner.h" +#include "private.h" +#include "wincompat.h" + +#include +#include + +#define PATH_TOKENS ":./" +#define CHUNK_SIZE 10 +#define FLOAT_PRECISION 10 + +#define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */ +#define _delete(P) free((void *)(P)) + +/* ------------------------------------------------------------------------- */ + +#ifdef WIN32 + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + return(TRUE); +} + +#endif + +/* ------------------------------------------------------------------------- */ + +static const char *__io_error = "file I/O error"; + +static void __config_list_destroy(config_list_t *list); +static void __config_write_setting(const config_setting_t *setting, + FILE *stream, int depth); + +extern int libconfig_yyparse(void *scanner, struct parse_context *ctx); + +/* ------------------------------------------------------------------------- */ + +static int __config_name_compare(const char *a, const char *b) +{ + const char *p, *q; + + for(p = a, q = b; ; p++, q++) + { + int pd = ((! *p) || strchr(PATH_TOKENS, *p)); + int qd = ((! *q) || strchr(PATH_TOKENS, *q)); + + if(pd && qd) + break; + else if(pd) + return(-1); + else if(qd) + return(1); + else if(*p < *q) + return(-1); + else if(*p > *q) + return(1); + } + + return(0); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_write_value(const config_value_t *value, int type, + int format, int depth, FILE *stream) +{ + char fbuf[64]; + + switch(type) + { + /* boolean */ + case CONFIG_TYPE_BOOL: + fputs(value->ival ? "true" : "false", stream); + break; + + /* int */ + case CONFIG_TYPE_INT: + switch(format) + { + case CONFIG_FORMAT_HEX: + fprintf(stream, "0x%lX", value->ival); + break; + + case CONFIG_FORMAT_DEFAULT: + default: + fprintf(stream, "%ld", value->ival); + break; + } + break; + + /* 64-bit int */ + case CONFIG_TYPE_INT64: + switch(format) + { + case CONFIG_FORMAT_HEX: + fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval); + break; + + case CONFIG_FORMAT_DEFAULT: + default: + fprintf(stream, INT64_FMT "L", value->llval); + break; + } + break; + + /* float */ + case CONFIG_TYPE_FLOAT: + { + char *q; + + snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval); + + q = strchr(fbuf, 'e'); + if(! q) + { + /* no exponent */ + + if(! strchr(fbuf, '.')) /* no decimal point */ + strcat(fbuf, ".0"); + else + { + /* has decimal point */ + + char *p; + + for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p) + { + if(*p != '0') + { + *(++p) = '\0'; + break; + } + } + } + } + + fputs(fbuf, stream); + break; + } + + /* string */ + case CONFIG_TYPE_STRING: + { + char *p; + + fputc('\"', stream); + + if(value->sval) + { + for(p = value->sval; *p; p++) + { + switch(*p) + { + case '\"': + case '\\': + fputc('\\', stream); + fputc(*p, stream); + break; + + case '\n': + fputs("\\n", stream); + break; + + case '\r': + fputs("\\r", stream); + break; + + case '\f': + fputs("\\f", stream); + break; + + case '\t': + fputs("\\t", stream); + break; + + default: + fputc(*p, stream); + } + } + } + fputc('\"', stream); + break; + } + + /* list */ + case CONFIG_TYPE_LIST: + { + config_list_t *list = value->list; + + fprintf(stream, "( "); + + if(list) + { + int len = list->length; + config_setting_t **s; + + for(s = list->elements; len--; s++) + { + __config_write_value(&((*s)->value), (*s)->type, (*s)->format, + depth + 1, stream); + + if(len) + fputc(',', stream); + + fputc(' ', stream); + } + } + + fputc(')', stream); + break; + } + + /* array */ + case CONFIG_TYPE_ARRAY: + { + config_list_t *list = value->list; + + fprintf(stream, "[ "); + + if(list) + { + int len = list->length; + config_setting_t **s; + + for(s = list->elements; len--; s++) + { + __config_write_value(&((*s)->value), (*s)->type, (*s)->format, + depth + 1, stream); + + if(len) + fputc(',', stream); + + fputc(' ', stream); + } + } + + fputc(']', stream); + break; + } + + /* group */ + case CONFIG_TYPE_GROUP: + { + config_list_t *list = value->list; + + if(depth > 0) + { + fputc('\n', stream); + + if(depth > 1) + fprintf(stream, "%*s", (depth - 1) * 2, " "); + fprintf(stream, "{\n"); + } + + if(list) + { + int len = list->length; + config_setting_t **s; + + for(s = list->elements; len--; s++) + __config_write_setting(*s, stream, depth + 1); + } + + if(depth > 1) + fprintf(stream, "%*s", (depth - 1) * 2, " "); + + if(depth > 0) + fputc('}', stream); + + break; + } + + default: + /* this shouldn't happen, but handle it gracefully... */ + fputs("???", stream); + break; + } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_add(config_list_t *list, config_setting_t *setting) +{ + if(list->length == list->capacity) + { + list->capacity += CHUNK_SIZE; + list->elements = (config_setting_t **)realloc( + list->elements, list->capacity * sizeof(config_setting_t *)); + } + + list->elements[list->length] = setting; + list->length++; +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *__config_list_search(config_list_t *list, + const char *name, + unsigned int *idx) +{ + config_setting_t **found = NULL; + unsigned int i; + + if(! list) + return(NULL); + + for(i = 0, found = list->elements; i < list->length; i++, found++) + { + if(! (*found)->name) + continue; + + if(! __config_name_compare(name, (*found)->name)) + { + if(idx) + *idx = i; + + return(*found); + } + } + + return(NULL); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_remove(config_list_t *list, int idx) +{ + int offset = (idx * sizeof(config_setting_t *)); + int len = list->length - 1 - idx; + char *base = (char *)list->elements + offset; + + memmove(base, base + sizeof(config_setting_t *), + len * sizeof(config_setting_t *)); + + list->length--; + + if((list->capacity - list->length) >= CHUNK_SIZE) + { + /* realloc smaller? */ + } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_setting_destroy(config_setting_t *setting) +{ + if(setting) + { + if(setting->name) + _delete(setting->name); + + if(setting->type == CONFIG_TYPE_STRING) + _delete(setting->value.sval); + + else if((setting->type == CONFIG_TYPE_GROUP) + || (setting->type == CONFIG_TYPE_ARRAY) + || (setting->type == CONFIG_TYPE_LIST)) + { + if(setting->value.list) + __config_list_destroy(setting->value.list); + } + + if(setting->hook && setting->config->destructor) + setting->config->destructor(setting->hook); + + _delete(setting); + } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_destroy(config_list_t *list) +{ + config_setting_t **p; + unsigned int i; + + if(! list) + return; + + if(list->elements) + { + for(p = list->elements, i = 0; i < list->length; p++, i++) + __config_setting_destroy(*p); + + _delete(list->elements); + } + + _delete(list); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_vector_checktype(const config_setting_t *vector, int type) +{ + /* if the array is empty, then it has no type yet */ + + if(! vector->value.list) + return(CONFIG_TRUE); + + if(vector->value.list->length == 0) + return(CONFIG_TRUE); + + /* if it's a list, any type is allowed */ + + if(vector->type == CONFIG_TYPE_LIST) + return(CONFIG_TRUE); + + /* otherwise the first element added determines the type of the array */ + + return((vector->value.list->elements[0]->type == type) + ? CONFIG_TRUE : CONFIG_FALSE); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_validate_name(const char *name) +{ + const char *p = name; + + if(*p == '\0') + return(CONFIG_FALSE); + + if(! isalpha(*p) && (*p != '*')) + return(CONFIG_FALSE); + + for(++p; *p; ++p) + { + if(! (isalpha(*p) || isdigit(*p) || strchr("*_-", (int)*p))) + return(CONFIG_FALSE); + } + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_read(config_t *config, FILE *stream) +{ + yyscan_t scanner; + struct parse_context ctx; + int r; + + /* Reinitialize the config (keep the destructor) */ + void (*destructor)(void *) = config->destructor; + config_destroy(config); + config_init(config); + config->destructor = destructor; + + ctx.config = config; + ctx.parent = config->root; + ctx.setting = config->root; + + libconfig_yylex_init(&scanner); + libconfig_yyrestart(stream, scanner); + r = libconfig_yyparse(scanner, &ctx); + libconfig_yylex_destroy(scanner); + + return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_write_setting(const config_setting_t *setting, + FILE *stream, int depth) +{ + if(depth > 1) + fprintf(stream, "%*s", (depth - 1) * 2, " "); + + if(setting->name) + { + fputs(setting->name, stream); + fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '=')); + } + + __config_write_value(&(setting->value), setting->type, setting->format, + depth, stream); + + if(depth > 0) + { + fputc(';', stream); + fputc('\n', stream); + } +} + +/* ------------------------------------------------------------------------- */ + +void config_write(const config_t *config, FILE *stream) +{ + __config_write_setting(config->root, stream, 0); +} + +/* ------------------------------------------------------------------------- */ + +int config_read_file(config_t *config, const char *filename) +{ + int ret; + FILE *f = fopen(filename, "rt"); + if(! f) + { + config->error_text = __io_error; + return(CONFIG_FALSE); + } + + ret = config_read(config, f); + fclose(f); + return(ret); +} + +/* ------------------------------------------------------------------------- */ + +int config_write_file(config_t *config, const char *filename) +{ + FILE *f = fopen(filename, "wt"); + if(! f) + { + config->error_text = __io_error; + return(CONFIG_FALSE); + } + + config_write(config, f); + fclose(f); + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +void config_destroy(config_t *config) +{ + __config_setting_destroy(config->root); + + memset((void *)config, 0, sizeof(config_t)); +} + +/* ------------------------------------------------------------------------- */ + +void config_init(config_t *config) +{ + memset((void *)config, 0, sizeof(config_t)); + + config->root = _new(config_setting_t); + config->root->type = CONFIG_TYPE_GROUP; + config->root->config = config; +} + +/* ------------------------------------------------------------------------- */ + +void config_set_auto_convert(config_t *config, int flag) +{ + if(flag) + config->flags |= CONFIG_OPTION_AUTOCONVERT; + else + config->flags &= ~CONFIG_OPTION_AUTOCONVERT; +} + +/* ------------------------------------------------------------------------- */ + +int config_get_auto_convert(const config_t *config) +{ + return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0); +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *config_setting_create(config_setting_t *parent, + const char *name, int type) +{ + config_setting_t *setting; + config_list_t *list; + + if((parent->type != CONFIG_TYPE_GROUP) + && (parent->type != CONFIG_TYPE_ARRAY) + && (parent->type != CONFIG_TYPE_LIST)) + return(NULL); + + setting = _new(config_setting_t); + setting->parent = parent; + setting->name = (name == NULL) ? NULL : strdup(name); + setting->type = type; + setting->config = parent->config; + setting->hook = NULL; + setting->line = 0; + + list = parent->value.list; + + if(! list) + list = parent->value.list = _new(config_list_t); + + __config_list_add(list, setting); + + return(setting); +} + +/* ------------------------------------------------------------------------- */ + +long config_setting_get_int(const config_setting_t *setting) +{ + switch(setting->type) + { + case CONFIG_TYPE_INT: + return(setting->value.ival); + + case CONFIG_TYPE_INT64: + if((setting->value.llval > INT32_MAX) + || (setting->value.llval < INT32_MIN)) + return(0); + else + return((long)setting->value.llval); + + case CONFIG_TYPE_FLOAT: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + return((long)(setting->value.fval)); + else + /* fall through */; + + default: + return(0); + } +} + +/* ------------------------------------------------------------------------- */ + +long long config_setting_get_int64(const config_setting_t *setting) +{ + switch(setting->type) + { + case CONFIG_TYPE_INT64: + return(setting->value.llval); + + case CONFIG_TYPE_INT: + return((long long)setting->value.ival); + + case CONFIG_TYPE_FLOAT: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + return((long long)(setting->value.fval)); + else + /* fall through */; + + default: + return(0); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_int(config_setting_t *setting, long value) +{ + switch(setting->type) + { + case CONFIG_TYPE_NONE: + setting->type = CONFIG_TYPE_INT; + /* fall through */ + + case CONFIG_TYPE_INT: + setting->value.ival = value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_FLOAT: + if(config_get_auto_convert(setting->config)) + { + setting->value.fval = (float)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_int64(config_setting_t *setting, long long value) +{ + switch(setting->type) + { + case CONFIG_TYPE_NONE: + setting->type = CONFIG_TYPE_INT64; + /* fall through */ + + case CONFIG_TYPE_INT64: + setting->value.llval = value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT: + if((value > INT32_MAX) || (value < INT32_MIN)) + setting->value.ival = 0; + else + setting->value.ival = (long)value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_FLOAT: + if(config_get_auto_convert(setting->config)) + { + setting->value.fval = (float)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +double config_setting_get_float(const config_setting_t *setting) +{ + switch(setting->type) + { + case CONFIG_TYPE_FLOAT: + return(setting->value.fval); + + case CONFIG_TYPE_INT: + if(config_get_auto_convert(setting->config)) + return((double)(setting->value.ival)); + else + return(0.0); + + case CONFIG_TYPE_INT64: + if(config_get_auto_convert(setting->config)) + return((double)(setting->value.llval)); + else + return(0.0); + + default: + return(0.0); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_float(config_setting_t *setting, double value) +{ + switch(setting->type) + { + case CONFIG_TYPE_NONE: + setting->type = CONFIG_TYPE_FLOAT; + /* fall through */ + + case CONFIG_TYPE_FLOAT: + setting->value.fval = value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + { + setting->value.ival = (long)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + case CONFIG_TYPE_INT64: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + { + setting->value.llval = (long long)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_bool(const config_setting_t *setting) +{ + return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_bool(config_setting_t *setting, int value) +{ + if(setting->type == CONFIG_TYPE_NONE) + setting->type = CONFIG_TYPE_BOOL; + else if(setting->type != CONFIG_TYPE_BOOL) + return(CONFIG_FALSE); + + setting->value.ival = value; + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_setting_get_string(const config_setting_t *setting) +{ + return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_string(config_setting_t *setting, const char *value) +{ + if(setting->type == CONFIG_TYPE_NONE) + setting->type = CONFIG_TYPE_STRING; + else if(setting->type != CONFIG_TYPE_STRING) + return(CONFIG_FALSE); + + if(setting->value.sval) + _delete(setting->value.sval); + + setting->value.sval = (value == NULL) ? NULL : strdup(value); + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_format(config_setting_t *setting, short format) +{ + if(((setting->type != CONFIG_TYPE_INT) + && (setting->type != CONFIG_TYPE_INT64)) + || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX))) + return(CONFIG_FALSE); + + setting->format = format; + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +short config_setting_get_format(config_setting_t *setting) +{ + return(setting->format); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_lookup(const config_t *config, const char *path) +{ + const char *p = path; + config_setting_t *setting = config->root, *found; + + for(;;) + { + while(*p && strchr(PATH_TOKENS, *p)) + p++; + + if(! *p) + break; + + if(*p == '[') + found = config_setting_get_elem(setting, atoi(++p)); + else + found = config_setting_get_member(setting, p); + + if(! found) + break; + + setting = found; + + while(! strchr(PATH_TOKENS, *p)) + p++; + } + + return(*p ? NULL : setting); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_lookup_string(const config_t *config, const char *path) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(NULL); + + return(config_setting_get_string(s)); +} + +/* ------------------------------------------------------------------------- */ + +long config_lookup_int(const config_t *config, const char *path) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(0); + + return(config_setting_get_int(s)); +} + +/* ------------------------------------------------------------------------- */ + +long long config_lookup_int64(const config_t *config, const char *path) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(INT64_CONST(0)); + + return(config_setting_get_int64(s)); +} + +/* ------------------------------------------------------------------------- */ + +double config_lookup_float(const config_t *config, const char *path) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(0.0); + + return(config_setting_get_float(s)); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_bool(const config_t *config, const char *path) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(0); + + return(config_setting_get_bool(s)); +} + +/* ------------------------------------------------------------------------- */ + +long config_setting_get_int_elem(const config_setting_t *vector, int idx) +{ + const config_setting_t *element = config_setting_get_elem(vector, idx); + + return(element ? config_setting_get_int(element) : 0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_int_elem(config_setting_t *vector, + int idx, long value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_INT)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_INT); + } + else + { + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + } + + if(! config_setting_set_int(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +long long config_setting_get_int64_elem(const config_setting_t *vector, + int idx) +{ + const config_setting_t *element = config_setting_get_elem(vector, idx); + + return(element ? config_setting_get_int64(element) : 0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_int64_elem(config_setting_t *vector, + int idx, long long value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64); + } + else + { + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + } + + if(! config_setting_set_int64(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +double config_setting_get_float_elem(const config_setting_t *vector, int idx) +{ + config_setting_t *element = config_setting_get_elem(vector, idx); + + return(element ? config_setting_get_float(element) : 0.0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_float_elem(config_setting_t *vector, + int idx, double value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT); + } + else + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(! config_setting_set_float(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_bool_elem(const config_setting_t *vector, int idx) +{ + config_setting_t *element = config_setting_get_elem(vector, idx); + + if(! element) + return(CONFIG_FALSE); + + if(element->type != CONFIG_TYPE_BOOL) + return(CONFIG_FALSE); + + return(element->value.ival); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_bool_elem(config_setting_t *vector, + int idx, int value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL); + } + else + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(! config_setting_set_bool(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_setting_get_string_elem(const config_setting_t *vector, + int idx) +{ + config_setting_t *element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(element->type != CONFIG_TYPE_STRING) + return(NULL); + + return(element->value.sval); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_string_elem(config_setting_t *vector, + int idx, const char *value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING); + } + else + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(! config_setting_set_string(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_get_elem(const config_setting_t *vector, + unsigned int idx) +{ + config_list_t *list = vector->value.list; + + if(((vector->type != CONFIG_TYPE_ARRAY) + && (vector->type != CONFIG_TYPE_LIST) + && (vector->type != CONFIG_TYPE_GROUP)) || ! list) + return(NULL); + + if(idx >= list->length) + return(NULL); + + return(list->elements[idx]); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_get_member(const config_setting_t *setting, + const char *name) +{ + if(setting->type != CONFIG_TYPE_GROUP) + return(NULL); + + return(__config_list_search(setting->value.list, name, NULL)); +} + +/* ------------------------------------------------------------------------- */ + +void config_set_destructor(config_t *config, void (*destructor)(void *)) +{ + config->destructor = destructor; +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_length(const config_setting_t *setting) +{ + if((setting->type != CONFIG_TYPE_GROUP) + && (setting->type != CONFIG_TYPE_ARRAY) + && (setting->type != CONFIG_TYPE_LIST)) + return(0); + + if(! setting->value.list) + return(0); + + return(setting->value.list->length); +} + +/* ------------------------------------------------------------------------- */ + +void config_setting_set_hook(config_setting_t *setting, void *hook) +{ + setting->hook = hook; +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_add(config_setting_t *parent, + const char *name, int type) +{ + if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST)) + return(NULL); + + if(! parent) + return(NULL); + + if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST)) + name = NULL; + + if(name) + { + if(! __config_validate_name(name)) + return(NULL); + } + + if(config_setting_get_member(parent, name) != NULL) + return(NULL); /* already exists */ + + return(config_setting_create(parent, name, type)); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_remove(config_setting_t *parent, const char *name) +{ + unsigned int idx; + config_setting_t *setting; + + if(! parent) + return(CONFIG_FALSE); + + if(parent->type != CONFIG_TYPE_GROUP) + return(CONFIG_FALSE); + + if(! (setting = __config_list_search(parent->value.list, name, &idx))) + return(CONFIG_FALSE); + + __config_setting_destroy(setting); + + __config_list_remove(parent->value.list, idx); + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_remove_elem(config_setting_t *parent, unsigned int idx) +{ + config_list_t *list = parent->value.list; + + if(((parent->type != CONFIG_TYPE_ARRAY) + && (parent->type != CONFIG_TYPE_LIST) + && (parent->type != CONFIG_TYPE_GROUP)) || ! list) + return(CONFIG_FALSE); + + if(idx >= list->length) + return(CONFIG_FALSE); + + __config_list_remove(list, idx); + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_index(const config_setting_t *setting) +{ + config_setting_t **found = NULL; + config_list_t *list; + int i; + + if(! setting->parent) + return(-1); + + list = setting->parent->value.list; + + for(i = 0, found = list->elements; i < list->length; ++i, ++found) + { + if(*found == setting) + return(i); + } + + return(-1); +} + +/* ------------------------------------------------------------------------- */ +/* eof */ Index: /tags/2.0-rc2/external/dbus/tools/introspect.h =================================================================== --- /tags/2.0-rc2/external/dbus/tools/introspect.h (revision 562) +++ /tags/2.0-rc2/external/dbus/tools/introspect.h (revision 562) @@ -0,0 +1,44 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_TOOLS_INTROSPECT_H +#define __DBUSXX_TOOLS_INTROSPECT_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +class IntrospectedObject : public DBus::IntrospectableProxy, public DBus::ObjectProxy +{ +public: + + IntrospectedObject( DBus::Connection& conn, const char* path, const char* service ) + : DBus::ObjectProxy(conn, path, service) + {} +}; + +#endif//__DBUSXX_TOOLS_INTROSPECT_H Index: /tags/2.0-rc2/external/dbus/tools/xml.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/tools/xml.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/tools/xml.cpp (revision 562) @@ -0,0 +1,315 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include "xml.h" + +#include + +#include + +std::istream& operator >> ( std::istream& in, DBus::Xml::Document& doc ) +{ + std::stringbuf xmlbuf; + in.get(xmlbuf, '\0'); + doc.from_xml(xmlbuf.str()); + + return in; +} + +std::ostream& operator << ( std::ostream& out, const DBus::Xml::Document& doc ) +{ + return out << doc.to_xml(); +} + +using namespace DBus; +using namespace DBus::Xml; + +Error::Error( const char* error, int line, int column ) +{ + std::ostringstream estream; + + estream << "line " << line << ", column " << column << ": " << error; + + _error = estream.str(); +} + +Node::Node( const char* n, const char** a ) +: name(n) +{ + if(a) + for(int i = 0; a[i]; i += 2) + { + _attrs[a[i]] = a[i+1]; + + //debug_log("xml:\t%s = %s", a[i], a[i+1]); + } +} + +Nodes Nodes::operator[]( const std::string& key ) +{ + Nodes result; + + for(iterator i = begin(); i != end(); ++i) + { + Nodes part = (**i)[key]; + + result.insert(result.end(), part.begin(), part.end()); + } + return result; +} + +Nodes Nodes::select( const std::string& attr, const std::string& value ) +{ + Nodes result; + + for(iterator i = begin(); i != end(); ++i) + { + if((*i)->get(attr) == value) + result.insert(result.end(), *i); + } + return result; +} + +Nodes Node::operator[]( const std::string& key ) +{ + Nodes result; + + if(key.length() == 0) return result; + + for(Children::iterator i = children.begin(); i != children.end(); ++i) + { + if(i->name == key) + result.push_back(&(*i)); + } + return result; +} + +std::string Node::get( const std::string& attribute ) +{ + if(_attrs.find(attribute) != _attrs.end()) + return _attrs[attribute]; + else + return ""; +} + +void Node::set( const std::string& attribute, std::string value ) +{ + if(value.length()) + _attrs[attribute] = value; + else + _attrs.erase(value); +} + +std::string Node::to_xml() const +{ + std::string xml; + int depth = 0; + + _raw_xml(xml, depth); + + return xml; +} + +void Node::_raw_xml( std::string& xml, int& depth ) const +{ + xml.append(depth*2, ' '); + xml.append("<"+name); + + for(Attributes::const_iterator i = _attrs.begin(); i != _attrs.end(); ++i) + { + xml.append(" "+i->first+"=\""+i->second+"\""); + } + + if(cdata.length() == 0 && children.size() == 0) + { + xml.append("/>\n"); + } + else + { + xml.append(">"); + + if(cdata.length()) + { + xml.append(cdata); + } + + if(children.size()) + { + xml.append("\n"); + depth++; + + for(Children::const_iterator i = children.begin(); i != children.end(); ++i) + { + i->_raw_xml(xml, depth); + } + + depth--; + xml.append(depth*2, ' '); + } + xml.append("\n"); + } +} + +Document::Document() +: root(0), _depth(0) +{ +} + +Document::Document( const std::string& xml ) +: root(0), _depth(0) +{ + from_xml(xml); +} + +Document::~Document() +{ + delete root; +} + +struct Document::Expat +{ + static void start_doctype_decl_handler( + void* data, const XML_Char* name, const XML_Char* sysid, const XML_Char* pubid, int has_internal_subset + ); + static void end_doctype_decl_handler( void* data ); + static void start_element_handler( void *data, const XML_Char *name, const XML_Char **atts ); + static void character_data_handler( void *data, const XML_Char* chars, int len ); + static void end_element_handler( void *data, const XML_Char *name ); +}; + +void Document::from_xml( const std::string& xml ) +{ + _depth = 0; + delete root; + root = 0; + + XML_Parser parser = XML_ParserCreate("UTF-8"); + + XML_SetUserData(parser, this); + + XML_SetDoctypeDeclHandler( + parser, + Document::Expat::start_doctype_decl_handler, + Document::Expat::end_doctype_decl_handler + ); + + XML_SetElementHandler( + parser, + Document::Expat::start_element_handler, + Document::Expat::end_element_handler + ); + + XML_SetCharacterDataHandler( + parser, + Document::Expat::character_data_handler + ); + + XML_Status status = XML_Parse(parser, xml.c_str(), xml.length(), true); + + if(status == XML_STATUS_ERROR) + { + const char* error = XML_ErrorString(XML_GetErrorCode(parser)); + int line = XML_GetCurrentLineNumber(parser); + int column = XML_GetCurrentColumnNumber(parser); + + XML_ParserFree(parser); + + throw Error(error, line, column); + } + else + { + XML_ParserFree(parser); + } +} + +std::string Document::to_xml() const +{ + return root->to_xml(); +} + +void Document::Expat::start_doctype_decl_handler( + void* data, const XML_Char* name, const XML_Char* sysid, const XML_Char* pubid, int has_internal_subset +) +{ +} + +void Document::Expat::end_doctype_decl_handler( void* data ) +{ +} + +void Document::Expat::start_element_handler( void *data, const XML_Char *name, const XML_Char **atts ) +{ + Document* doc = (Document*)data; + + //debug_log("xml:%d -> %s", doc->_depth, name); + + if(!doc->root) + { + doc->root = new Node(name, atts); + } + else + { + Node::Children* cld = &(doc->root->children); + + for(int i = 1; i < doc->_depth; ++i) + { + cld = &(cld->back().children); + } + cld->push_back(Node(name, atts)); + + //std::cerr << doc->to_xml() << std::endl; + } + doc->_depth++; +} + +void Document::Expat::character_data_handler( void *data, const XML_Char* chars, int len ) +{ + Document* doc = (Document*)data; + + Node* nod = doc->root; + + for(int i = 1; i < doc->_depth; ++i) + { + nod = &(nod->children.back()); + } + int x, y; + + x = 0; + y = len-1; + + while(isspace(chars[y]) && y > 0) --y; + while(isspace(chars[x]) && x < y) ++x; + + nod->cdata = std::string(chars, x, y+1); +} + +void Document::Expat::end_element_handler( void *data, const XML_Char *name ) +{ + Document* doc = (Document*)data; + + //debug_log("xml:%d <- %s", doc->_depth, name); + + doc->_depth--; +} + Index: /tags/2.0-rc2/external/dbus/tools/xml.h =================================================================== --- /tags/2.0-rc2/external/dbus/tools/xml.h (revision 562) +++ /tags/2.0-rc2/external/dbus/tools/xml.h (revision 562) @@ -0,0 +1,142 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_XML_H +#define __DBUSXX_XML_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +namespace DBus { + +namespace Xml { + +class Error : public std::exception +{ +public: + + Error( const char* error, int line, int column ); + + ~Error() throw() + {} + + const char* what() const throw() + { + return _error.c_str(); + } + +private: + + std::string _error; +}; + +class Node; + +class Nodes : public std::vector +{ +public: + + Nodes operator[]( const std::string& key ); + + Nodes select( const std::string& attr, const std::string& value ); +}; + +class Node +{ +public: + + typedef std::map Attributes; + + typedef std::vector Children; + + std::string name; + std::string cdata; + Children children; + + Node( std::string& n, Attributes& a ) + : name(n), _attrs(a) + {} + + Node( const char* n, const char** a = NULL ); + + Nodes operator[]( const std::string& key ); + + std::string get( const std::string& attribute ); + + void set( const std::string& attribute, std::string value ); + + std::string to_xml() const; + + Node& add( Node child ) + { + children.push_back(child); + return children.back(); + } + +private: + + void _raw_xml( std::string& xml, int& depth ) const; + + Attributes _attrs; +}; + +class Document +{ +public: + + struct Expat; + + Node* root; + + Document(); + + Document( const std::string& xml ); + + ~Document(); + + void from_xml( const std::string& xml ); + + std::string to_xml() const; + +private: + + int _depth; +}; + +} /* namespace Xml */ + +} /* namespace DBus */ + +std::istream& operator >> ( std::istream&, DBus::Xml::Document& ); +std::ostream& operator << ( std::ostream&, DBus::Xml::Document& ); + +#endif//__DBUSXX_XML_H Index: /tags/2.0-rc2/external/dbus/tools/xml2cpp.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/tools/xml2cpp.cpp (revision 1235) +++ /tags/2.0-rc2/external/dbus/tools/xml2cpp.cpp (revision 1235) @@ -0,0 +1,975 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include "xml2cpp.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace DBus; + +static const char* tab = " "; + +static const char* header = "\n\ +/*\n\ + * This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!\n\ + */\n\ +\n\ +"; + +static const char* dbus_includes = "\n\ +#include \n\ +\n\ +"; + +typedef map TypeCache; + +void usage( const char* argv0 ) +{ + cerr << endl << "Usage: " << argv0 << " [ --proxy= ] [ --adaptor= ]" + << endl << endl; + exit(-1); +} + +void underscorize( string& str ) +{ + for(unsigned int i = 0; i < str.length(); ++i) + { + if(!isalpha(str[i]) && !isdigit(str[i])) str[i] = '_'; + } +} + +string stub_name( string name ) +{ + underscorize(name); + + return "_" + name + "_stub"; +} + +int char_to_atomic_type( char t ) +{ + if(strchr("ybnqiuxtdsgavre", t)) + return t; + + return DBUS_TYPE_INVALID; +} + +const char* atomic_type_to_string( char t ) +{ + static struct { const char type; const char *name; } atos[] = + { + { 'y', "::DBus::Byte" }, + { 'b', "::DBus::Bool" }, + { 'n', "::DBus::Int16" }, + { 'q', "::DBus::UInt16" }, + { 'i', "::DBus::Int32" }, + { 'u', "::DBus::UInt32" }, + { 'x', "::DBus::Int64" }, + { 't', "::DBus::UInt64" }, + { 'd', "::DBus::Double" }, + { 's', "::DBus::String" }, + { 'o', "::DBus::Path" }, + { 'g', "::DBus::Signature" }, + { 'v', "::DBus::Variant" }, + { '\0', "" } + }; + int i; + + for(i = 0; atos[i].type; ++i) + { + if(atos[i].type == t) break; + } + return atos[i].name; +} + +bool is_atomic_type( const string& type ) +{ + return type.length() == 1 && char_to_atomic_type(type[0]) != DBUS_TYPE_INVALID; +} + +void _parse_signature( const string& signature, string& type, unsigned int& i ) +{ + for(; i < signature.length(); ++i) + { + switch(signature[i]) + { + case 'a': + { + switch(signature[++i]) + { + case '{': + { + type += "std::map< "; + + const char* atom = atomic_type_to_string(signature[++i]); + if(!atom) + { + cerr << "invalid signature" << endl; + exit(-1); + } + type += atom; + type += ", "; + ++i; + break; + } + default: + { + type += "std::vector< "; + break; + } + } + _parse_signature(signature, type, i); + type += " >"; + continue; + } + case '(': + { + type += "::DBus::Struct< "; + ++i; + _parse_signature(signature, type, i); + type += " >"; + continue; + } + case ')': + case '}': + { + return; + } + default: + { + const char* atom = atomic_type_to_string(signature[i]); + if(!atom) + { + cerr << "invalid signature" << endl; + exit(-1); + } + type += atom; + + if(signature[i+1] != ')' && signature[i+1] != '}' && i+1 < signature.length()) + { + type += ", "; + } + break; + } + } + } +} + +string signature_to_type( const string& signature ) +{ + string type; + unsigned int i = 0; + _parse_signature(signature, type, i); + return type; +} + +void generate_proxy( Xml::Document& doc, const char* filename ) +{ + cerr << "writing " << filename << endl; + + ofstream file(filename); + if(file.bad()) + { + cerr << "unable to write file " << filename << endl; + exit(-1); + } + + file << header; + string filestring = filename; + underscorize(filestring); + + string cond_comp = "__dbusxx__" + filestring + "__PROXY_MARSHAL_H"; + + file << "#ifndef " << cond_comp << endl; + file << "#define " << cond_comp << endl; + + file << dbus_includes; + + Xml::Node& root = *(doc.root); + Xml::Nodes interfaces = root["interface"]; + + for(Xml::Nodes::iterator i = interfaces.begin(); i != interfaces.end(); ++i) + { + Xml::Node& iface = **i; + Xml::Nodes methods = iface["method"]; + Xml::Nodes signals = iface["signal"]; + Xml::Nodes properties = iface["property"]; + Xml::Nodes ms; + ms.insert(ms.end(), methods.begin(), methods.end()); + ms.insert(ms.end(), signals.begin(), signals.end()); + + string ifacename = iface.get("name"); + if(ifacename == "org.freedesktop.DBus.Introspectable" + ||ifacename == "org.freedesktop.DBus.Properties") + { + cerr << "skipping interface " << ifacename << endl; + continue; + } + + istringstream ss(ifacename); + string nspace; + unsigned int nspaces = 0; + + while(ss.str().find('.', ss.tellg()) != string::npos) + { + getline(ss, nspace, '.'); + + file << "namespace " << nspace << " {" << endl; + + ++nspaces; + } + file << endl; + + string ifaceclass; + + getline(ss, ifaceclass); + + cerr << "generating code for interface " << ifacename << "..." << endl; + + file << "class " << ifaceclass << endl + << " : public ::DBus::InterfaceProxy" << endl + << "{" << endl + << "public:" << endl + << endl + << tab << ifaceclass << "()" << endl + << tab << ": ::DBus::InterfaceProxy(\"" << ifacename << "\")" << endl + << tab << "{" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& signal = **si; + + string marshname = "_" + signal.get("name") + "_stub"; + + file << tab << tab << "connect_signal(" + << ifaceclass << ", " << signal.get("name") << ", " << stub_name(signal.get("name")) + << ");" << endl; + } + + file << tab << "}" << endl + << endl; + + file << "public:" << endl + << endl + << tab << "/* methods exported by this interface," << endl + << tab << " * this functions will invoke the corresponding methods on the remote objects" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + Xml::Nodes args_in = args.select("direction","in"); + Xml::Nodes args_out = args.select("direction","out"); + + if(args_out.size() == 0 || args_out.size() > 1 ) + { + file << tab << "void "; + } + else if(args_out.size() == 1) + { + file << tab << signature_to_type(args_out.front()->get("type")) << " "; + } + + file << method.get("name") << "( "; + + unsigned int i = 0; + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << "const " << signature_to_type(arg.get("type")) << "& "; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << arg_name; + else + file << "argin" << i; + + if((i+1 != args_in.size() || args_out.size() > 1)) + file << ", "; + } + + if(args_out.size() > 1) + { + unsigned int i = 0; + for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i) + { + Xml::Node& arg = **ao; + file << signature_to_type(arg.get("type")) << "&"; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << " " << arg_name; + else + file << " argout" << i; + + if(i+1 != args_out.size()) + file << ", "; + } + } + file << " )" << endl; + + file << tab << "{" << endl + << tab << tab << "::DBus::CallMessage call;" << endl; + + if(args_in.size() > 0) + { + file << tab << tab << "::DBus::MessageIter wi = call.writer();" << endl + << endl; + } + + unsigned int j = 0; + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++j) + { + Xml::Node& arg = **ai; + string arg_name = arg.get("name"); + if(arg_name.length()) + file << tab << tab << "wi << " << arg_name << ";" << endl; + else + file << tab << tab << "wi << argin" << j << ";" << endl; + } + + file << tab << tab << "call.member(\"" << method.get("name") << "\");" << endl + << tab << tab << "::DBus::Message ret = invoke_method(call);" << endl; + + + if(args_out.size() > 0) + { + file << tab << tab << "::DBus::MessageIter ri = ret.reader();" << endl + << endl; + } + + if(args_out.size() == 1) + { + file << tab << tab << signature_to_type(args_out.front()->get("type")) << " argout;" << endl; + file << tab << tab << "ri >> argout;" << endl; + file << tab << tab << "return argout;" << endl; + } + else if(args_out.size() > 1) + { + unsigned int i = 0; + for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i) + { + Xml::Node& arg = **ao; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << tab << tab << "ri >> " << arg.get("name") << ";" << endl; + else + file << tab << tab << "ri >> argout" << i << ";" << endl; + } + } + + file << tab << "}" << endl + << endl; + } + + file << endl + << "public:" << endl + << endl + << tab << "/* signal handlers for this interface" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& signal = **si; + Xml::Nodes args = signal["arg"]; + + file << tab << "virtual void " << signal.get("name") << "( "; + + unsigned int i = 0; + for(Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << "const " << signature_to_type(arg.get("type")) << "& "; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << arg_name; + else + file << "argin" << i; + + if((ai+1 != args.end())) + file << ", "; + } + file << " ) = 0;" << endl; + } + + file << endl + << "private:" << endl + << endl + << tab << "/* unmarshalers (to unpack the DBus message before calling the actual signal handler)" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& signal = **si; + Xml::Nodes args = signal["arg"]; + + file << tab << "void " << stub_name(signal.get("name")) << "( const ::DBus::SignalMessage& sig )" << endl + << tab << "{" << endl; + + if(args.size() > 0) + { + file << tab << tab << "::DBus::MessageIter ri = sig.reader();" << endl + << endl; + } + + unsigned int i = 0; + for(Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << tab << tab << signature_to_type(arg.get("type")) << " " ; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << arg_name << ";" << " ri >> " << arg_name << ";" << endl; + else + file << "arg" << i << ";" << " ri >> " << "arg" << i << ";" << endl; + } + + file << tab << tab << signal.get("name") << "("; + + unsigned int j = 0; + for(Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai, ++j) + { + Xml::Node& arg = **ai; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << arg_name; + else + file << "arg" << j; + + if(ai+1 != args.end()) + file << ", "; + } + + file << ");" << endl; + + file << tab << "}" << endl; + } + + + file << "};" << endl + << endl; + + for(unsigned int i = 0; i < nspaces; ++i) + { + file << "} "; + } + file << endl; + } + + file << "#endif//" << cond_comp << endl; + + file.close(); +} + +void generate_adaptor( Xml::Document& doc, const char* filename ) +{ + cerr << "writing " << filename << endl; + + ofstream file(filename); + if(file.bad()) + { + cerr << "unable to write file " << filename << endl; + exit(-1); + } + + file << header; + string filestring = filename; + underscorize(filestring); + + string cond_comp = "__dbusxx__" + filestring + "__ADAPTOR_MARSHAL_H"; + + file << "#ifndef " << cond_comp << endl + << "#define " << cond_comp << endl; + + file << dbus_includes; + + Xml::Node& root = *(doc.root); + Xml::Nodes interfaces = root["interface"]; + + for(Xml::Nodes::iterator i = interfaces.begin(); i != interfaces.end(); ++i) + { + Xml::Node& iface = **i; + Xml::Nodes methods = iface["method"]; + Xml::Nodes signals = iface["signal"]; + Xml::Nodes properties = iface["property"]; + Xml::Nodes ms; + ms.insert(ms.end(), methods.begin(), methods.end()); + ms.insert(ms.end(), signals.begin(), signals.end()); + + string ifacename = iface.get("name"); + if(ifacename == "org.freedesktop.DBus.Introspectable" + ||ifacename == "org.freedesktop.DBus.Properties") + { + cerr << "skipping interface " << ifacename << endl; + continue; + } + + istringstream ss(ifacename); + string nspace; + unsigned int nspaces = 0; + + while(ss.str().find('.', ss.tellg()) != string::npos) + { + getline(ss, nspace, '.'); + + file << "namespace " << nspace << " {" << endl; + + ++nspaces; + } + file << endl; + + string ifaceclass; + + getline(ss, ifaceclass); + + cerr << "generating code for interface " << ifacename << "..." << endl; + + file << "class " << ifaceclass << endl + << ": public ::DBus::InterfaceAdaptor" << endl + << "{" << endl + << "public:" << endl + << endl + << tab << ifaceclass << "()" << endl + << tab << ": ::DBus::InterfaceAdaptor(\"" << ifacename << "\")" << endl + << tab << "{" << endl; + + for(Xml::Nodes::iterator pi = properties.begin(); pi != properties.end(); ++pi) + { + Xml::Node& property = **pi; + + file << tab << tab << "bind_property(" + << property.get("name") << ", " + << "\"" << property.get("type") << "\", " + << ( property.get("access").find("read") != string::npos + ? "true" + : "false" ) + << ", " + << ( property.get("access").find("write") != string::npos + ? "true" + : "false" ) + << ");" << endl; + } + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + + file << tab << tab << "register_method(" + << ifaceclass << ", " << method.get("name") << ", "<< stub_name(method.get("name")) + << ");" << endl; + } + + file << tab << "}" << endl + << endl; + + file << tab << "::DBus::IntrospectedInterface* const introspect() const " << endl + << tab << "{" << endl; + + for(Xml::Nodes::iterator mi = ms.begin(); mi != ms.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + + file << tab << tab << "static ::DBus::IntrospectedArgument " << method.get("name") << "_args[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai) + { + Xml::Node& arg = **ai; + + file << tab << tab << tab << "{ "; + + if(arg.get("name").length()) + { + file << "\"" << arg.get("name") << "\", "; + } + else + { + file << "0, "; + } + file << "\"" << arg.get("type") << "\", " + << ( arg.get("direction") == "in" ? "true" : "false" ) + << " }," << endl; + } + file << tab << tab << tab << "{ 0, 0, 0 }" << endl + << tab << tab << "};" << endl; + } + + file << tab << tab << "static ::DBus::IntrospectedMethod " << ifaceclass << "_methods[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + + file << tab << tab << tab << "{ \"" << method.get("name") << "\", " << method.get("name") << "_args }," << endl; + } + + file << tab << tab << tab << "{ 0, 0 }" << endl + << tab << tab << "};" << endl; + + file << tab << tab << "static ::DBus::IntrospectedMethod " << ifaceclass << "_signals[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& method = **si; + + file << tab << tab << tab << "{ \"" << method.get("name") << "\", " << method.get("name") << "_args }," << endl; + } + + file << tab << tab << tab << "{ 0, 0 }" << endl + << tab << tab << "};" << endl; + + file << tab << tab << "static ::DBus::IntrospectedProperty " << ifaceclass << "_properties[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator pi = properties.begin(); pi != properties.end(); ++pi) + { + Xml::Node& property = **pi; + + file << tab << tab << tab << "{ " + << "\"" << property.get("name") << "\", " + << "\"" << property.get("type") << "\", " + << ( property.get("access").find("read") != string::npos + ? "true" + : "false" ) + << ", " + << ( property.get("access").find("write") != string::npos + ? "true" + : "false" ) + << " }," << endl; + } + + + file << tab << tab << tab << "{ 0, 0, 0, 0 }" << endl + << tab << tab << "};" << endl; + + file << tab << tab << "static ::DBus::IntrospectedInterface " << ifaceclass << "_interface = " << endl + << tab << tab << "{" << endl + << tab << tab << tab << "\"" << ifacename << "\"," << endl + << tab << tab << tab << ifaceclass << "_methods," << endl + << tab << tab << tab << ifaceclass << "_signals," << endl + << tab << tab << tab << ifaceclass << "_properties" << endl + << tab << tab << "};" << endl + << tab << tab << "return &" << ifaceclass << "_interface;" << endl + << tab << "}" << endl + << endl; + + file << "public:" << endl + << endl + << tab << "/* properties exposed by this interface, use" << endl + << tab << " * property() and property(value) to get and set a particular property" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator pi = properties.begin(); pi != properties.end(); ++pi) + { + Xml::Node& property = **pi; + string name = property.get("name"); + string type = property.get("type"); + string type_name = signature_to_type(type); + + file << tab << "::DBus::PropertyAdaptor< " << type_name << " > " << name << ";" << endl; + } + + file << endl; + + file << "public:" << endl + << endl + << tab << "/* methods exported by this interface," << endl + << tab << " * you will have to implement them in your ObjectAdaptor" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + Xml::Nodes args_in = args.select("direction","in"); + Xml::Nodes args_out = args.select("direction","out"); + + file << tab << "virtual "; + + if(args_out.size() == 0 || args_out.size() > 1 ) + { + file << "void "; + } + else if(args_out.size() == 1) + { + file << signature_to_type(args_out.front()->get("type")) << " "; + } + + file << method.get("name") << "( "; + + unsigned int i = 0; + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << "const " << signature_to_type(arg.get("type")) << "& "; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << arg_name; + + if((i+1 != args_in.size() || args_out.size() > 1)) + file << ", "; + } + + if(args_out.size() > 1) + { + unsigned int i = 0; + for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i) + { + Xml::Node& arg = **ao; + file << signature_to_type(arg.get("type")) << "&"; + + string arg_name = arg.get("name"); + if(arg_name.length()) + file << " " << arg_name; + + if(i+1 != args_out.size()) + file << ", "; + } + } + file << " ) = 0;" << endl; + } + + file << endl + << "public:" << endl + << endl + << tab << "/* signal emitters for this interface" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& signal = **si; + Xml::Nodes args = signal["arg"]; + + file << tab << "void " << signal.get("name") << "( "; + + unsigned int i = 0; + for(Xml::Nodes::iterator a = args.begin(); a != args.end(); ++a, ++i) + { + Xml::Node& arg = **a; + + file << "const " << signature_to_type(arg.get("type")) << "& arg" << i+1; + + if(i+1 != args.size()) + file << ", "; + } + + file << " )" << endl + << tab << "{" << endl + << tab << tab << "::DBus::SignalMessage sig(\"" << signal.get("name") <<"\");" << endl;; + + + if(args.size() > 0) + { + file << tab << tab << "::DBus::MessageIter wi = sig.writer();" << endl; + + for(unsigned int i = 0; i < args.size(); ++i) + { + file << tab << tab << "wi << arg" << i+1 << ";" << endl; + } + } + + file << tab << tab << "emit_signal(sig);" << endl + << tab << "}" << endl; + } + + file << endl + << "private:" << endl + << endl + << tab << "/* unmarshalers (to unpack the DBus message before calling the actual interface method)" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + Xml::Nodes args_in = args.select("direction","in"); + Xml::Nodes args_out = args.select("direction","out"); + + file << tab << "::DBus::Message " << stub_name(method.get("name")) << "( const ::DBus::CallMessage& call )" << endl + << tab << "{" << endl + << tab << tab << "::DBus::MessageIter ri = call.reader();" << endl + << endl; + + unsigned int i = 1; + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << tab << tab << signature_to_type(arg.get("type")) << " argin" << i << ";" + << " ri >> argin" << i << ";" << endl; + } + + if(args_out.size() == 0) + { + file << tab << tab; + } + else if(args_out.size() == 1) + { + file << tab << tab << signature_to_type(args_out.front()->get("type")) << " argout1 = "; + } + else + { + unsigned int i = 1; + for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i) + { + Xml::Node& arg = **ao; + file << tab << tab << signature_to_type(arg.get("type")) << " argout" << i << ";" << endl; + } + file << tab << tab; + } + + file << method.get("name") << "("; + + for(unsigned int i = 0; i < args_in.size(); ++i) + { + file << "argin" << i+1; + + if((i+1 != args_in.size() || args_out.size() > 1)) + file << ", "; + } + + if(args_out.size() > 1) + for(unsigned int i = 0; i < args_out.size(); ++i) + { + file << "argout" << i+1; + + if(i+1 != args_out.size()) + file << ", "; + } + + file << ");" << endl; + + file << tab << tab << "::DBus::ReturnMessage reply(call);" << endl; + + if(args_out.size() > 0) + { + file << tab << tab << "::DBus::MessageIter wi = reply.writer();" << endl; + + for(unsigned int i = 0; i < args_out.size(); ++i) + { + file << tab << tab << "wi << argout" << i+1 << ";" << endl; + } + } + + file << tab << tab << "return reply;" << endl; + + file << tab << "}" << endl; + } + + file << "};" << endl + << endl; + + for(unsigned int i = 0; i < nspaces; ++i) + { + file << "} "; + } + file << endl; + } + + file << "#endif//" << cond_comp << endl; + + file.close(); +} + +int main( int argc, char** argv ) +{ + if(argc < 2) + { + usage(argv[0]); + } + + bool proxy_mode, adaptor_mode; + char *proxy, *adaptor; + + proxy_mode = false; + proxy = 0; + + adaptor_mode = false; + adaptor = 0; + + for(int a = 1; a < argc; ++a) + { + if(!strncmp(argv[a], "--proxy=", 8)) + { + proxy_mode = true; + proxy = argv[a] +8; + } + else + if(!strncmp(argv[a], "--adaptor=", 10)) + { + adaptor_mode = true; + adaptor = argv[a] +10; + } + } + + if(!proxy_mode && !adaptor_mode) usage(argv[0]); + + ifstream xmlfile(argv[1]); + + if(xmlfile.bad()) + { + cerr << "unable to open file " << argv[1] << endl; + return -1; + } + + Xml::Document doc; + + try + { + xmlfile >> doc; + //cout << doc.to_xml(); + } + catch(Xml::Error& e) + { + cerr << "error parsing " << argv[1] << ": " << e.what() << endl; + return -1; + } + + if(!doc.root) + { + cerr << "empty document" << endl; + return -1; + } + + if(proxy_mode) generate_proxy(doc, proxy); + if(adaptor_mode) generate_adaptor(doc, adaptor); + + return 0; +} Index: /tags/2.0-rc2/external/dbus/tools/introspect.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/tools/introspect.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/tools/introspect.cpp (revision 562) @@ -0,0 +1,78 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + +#include +#include +#include +#include "introspect.h" + +DBus::BusDispatcher dispatcher; +static bool systembus; +static char* path; +static char* service; + +void niam( int sig ) +{ + DBus::Connection conn = systembus ? DBus::Connection::SystemBus() : DBus::Connection::SessionBus(); + + IntrospectedObject io(conn, path, service); + + std::cout << io.Introspect(); + + dispatcher.leave(); +} + +int main( int argc, char** argv ) +{ + signal(SIGTERM, niam); + signal(SIGINT, niam); + signal(SIGALRM, niam); + + if(argc == 1) + { + std::cerr << std::endl << "Usage: " << argv[0] << " [--system] []" << std::endl << std::endl; + } + else + { + if(strcmp(argv[1], "--system")) + { + systembus = false; + path = argv[1]; + service = argc > 2 ? argv[2] : 0; + } + else + { + systembus = true; + path = argv[2]; + service = argc > 3 ? argv[3] : 0; + } + + DBus::default_dispatcher = &dispatcher; + + alarm(1); + + dispatcher.enter(); + } + + return 0; +} Index: /tags/2.0-rc2/external/dbus/tools/xml2cpp.h =================================================================== --- /tags/2.0-rc2/external/dbus/tools/xml2cpp.h (revision 562) +++ /tags/2.0-rc2/external/dbus/tools/xml2cpp.h (revision 562) @@ -0,0 +1,37 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_TOOLS_XML2CPP_H +#define __DBUSXX_TOOLS_XML2CPP_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "xml.h" + +#endif//__DBUSXX_TOOLS_XML2CPP_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/error.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/error.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/error.h (revision 562) @@ -0,0 +1,289 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_ERROR_H +#define __DBUSXX_ERROR_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "util.h" + +#include + +namespace DBus { + +class Message; +class InternalError; + +class DXXAPI Error : public std::exception +{ +public: + + Error(); + + Error( InternalError& ); + + Error( const char* name, const char* message ); + + Error( Message& ); + + ~Error() throw(); + + const char* what() const throw(); + + const char* name() const; + + const char* message() const; + + void set( const char* name, const char* message ); + // parameters MUST be static strings + + bool is_set() const; + + operator bool() const + { + return is_set(); + } + +private: + + RefPtrI _int; +}; + +struct DXXAPI ErrorFailed : public Error +{ + ErrorFailed( const char* message ) + : Error("org.freedesktop.DBus.Error.Failed", message) + {} +}; + +struct DXXAPI ErrorNoMemory : public Error +{ + ErrorNoMemory( const char* message ) + : Error("org.freedesktop.DBus.Error.NoMemory", message) + {} +}; + +struct DXXAPI ErrorServiceUnknown : public Error +{ + ErrorServiceUnknown( const char* message ) + : Error("org.freedesktop.DBus.Error.ServiceUnknown", message) + {} +}; + +struct DXXAPI ErrorNameHasNoOwner : public Error +{ + ErrorNameHasNoOwner( const char* message ) + : Error("org.freedesktop.DBus.Error.NameHasNoOwner", message) + {} +}; + +struct DXXAPI ErrorNoReply : public Error +{ + ErrorNoReply( const char* message ) + : Error("org.freedesktop.DBus.Error.NoReply", message) + {} +}; + +struct DXXAPI ErrorIOError : public Error +{ + ErrorIOError( const char* message ) + : Error("org.freedesktop.DBus.Error.IOError", message) + {} +}; + +struct DXXAPI ErrorBadAddress : public Error +{ + ErrorBadAddress( const char* message ) + : Error("org.freedesktop.DBus.Error.BadAddress", message) + {} +}; + +struct DXXAPI ErrorNotSupported : public Error +{ + ErrorNotSupported( const char* message ) + : Error("org.freedesktop.DBus.Error.NotSupported", message) + {} +}; + +struct DXXAPI ErrorLimitsExceeded : public Error +{ + ErrorLimitsExceeded( const char* message ) + : Error("org.freedesktop.DBus.Error.LimitsExceeded", message) + {} +}; + +struct DXXAPI ErrorAccessDenied : public Error +{ + ErrorAccessDenied( const char* message ) + : Error("org.freedesktop.DBus.Error.AccessDenied", message) + {} +}; + +struct DXXAPI ErrorAuthFailed : public Error +{ + ErrorAuthFailed( const char* message ) + : Error("org.freedesktop.DBus.Error.AuthFailed", message) + {} +}; + +struct DXXAPI ErrorNoServer : public Error +{ + ErrorNoServer( const char* message ) + : Error("org.freedesktop.DBus.Error.NoServer", message) + {} +}; + +struct DXXAPI ErrorTimeout : public Error +{ + ErrorTimeout( const char* message ) + : Error("org.freedesktop.DBus.Error.Timeout", message) + {} +}; + +struct DXXAPI ErrorNoNetwork : public Error +{ + ErrorNoNetwork( const char* message ) + : Error("org.freedesktop.DBus.Error.NoNetwork", message) + {} +}; + +struct DXXAPI ErrorAddressInUse : public Error +{ + ErrorAddressInUse( const char* message ) + : Error("org.freedesktop.DBus.Error.AddressInUse", message) + {} +}; + +struct DXXAPI ErrorDisconnected : public Error +{ + ErrorDisconnected( const char* message ) + : Error("org.freedesktop.DBus.Error.Disconnected", message) + {} +}; + +struct DXXAPI ErrorInvalidArgs : public Error +{ + ErrorInvalidArgs( const char* message ) + : Error("org.freedesktop.DBus.Error.InvalidArgs", message) + {} +}; + +struct DXXAPI ErrorFileNotFound : public Error +{ + ErrorFileNotFound( const char* message ) + : Error("org.freedesktop.DBus.Error.FileNotFound", message) + {} +}; + +struct DXXAPI ErrorUnknownMethod : public Error +{ + ErrorUnknownMethod( const char* message ) + : Error("org.freedesktop.DBus.Error.UnknownMethod", message) + {} +}; + +struct DXXAPI ErrorTimedOut : public Error +{ + ErrorTimedOut( const char* message ) + : Error("org.freedesktop.DBus.Error.TimedOut", message) + {} +}; + +struct DXXAPI ErrorMatchRuleNotFound : public Error +{ + ErrorMatchRuleNotFound( const char* message ) + : Error("org.freedesktop.DBus.Error.MatchRuleNotFound", message) + {} +}; + +struct DXXAPI ErrorMatchRuleInvalid : public Error +{ + ErrorMatchRuleInvalid( const char* message ) + : Error("org.freedesktop.DBus.Error.MatchRuleInvalid", message) + {} +}; + +struct DXXAPI ErrorSpawnExecFailed : public Error +{ + ErrorSpawnExecFailed( const char* message ) + : Error("org.freedesktop.DBus.Error.Spawn.ExecFailed", message) + {} +}; + +struct DXXAPI ErrorSpawnForkFailed : public Error +{ + ErrorSpawnForkFailed( const char* message ) + : Error("org.freedesktop.DBus.Error.Spawn.ForkFailed", message) + {} +}; + +struct DXXAPI ErrorSpawnChildExited : public Error +{ + ErrorSpawnChildExited( const char* message ) + : Error("org.freedesktop.DBus.Error.Spawn.ChildExited", message) + {} +}; + +struct DXXAPI ErrorSpawnChildSignaled : public Error +{ + ErrorSpawnChildSignaled( const char* message ) + : Error("org.freedesktop.DBus.Error.Spawn.ChildSignaled", message) + {} +}; + +struct DXXAPI ErrorSpawnFailed : public Error +{ + ErrorSpawnFailed( const char* message ) + : Error("org.freedesktop.DBus.Error.Spawn.Failed", message) + {} +}; + +struct DXXAPI ErrorInvalidSignature : public Error +{ + ErrorInvalidSignature( const char* message ) + : Error("org.freedesktop.DBus.Error.InvalidSignature", message) + {} +}; + +struct DXXAPI ErrorUnixProcessIdUnknown : public Error +{ + ErrorUnixProcessIdUnknown( const char* message ) + : Error("org.freedesktop.DBus.Error.UnixProcessIdUnknown", message) + {} +}; + +struct DXXAPI ErrorSELinuxSecurityContextUnknown : public Error +{ + ErrorSELinuxSecurityContextUnknown( const char* message ) + : Error("org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", message) + {} +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_ERROR_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/dbus.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/dbus.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/dbus.h (revision 562) @@ -0,0 +1,48 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_DBUS_H +#define __DBUSXX_DBUS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "types.h" +#include "interface.h" +#include "object.h" +#include "property.h" +#include "connection.h" +#include "server.h" +#include "error.h" +#include "message.h" +#include "debug.h" +#include "pendingcall.h" +#include "server.h" +#include "util.h" +#include "dispatcher.h" +#include "eventloop.h" +#include "introspection.h" + +#endif//__DBUSXX_DBUS_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/glib-integration.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/glib-integration.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/glib-integration.h (revision 562) @@ -0,0 +1,119 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_GLIB_INTEGRATION_H +#define __DBUSXX_GLIB_INTEGRATION_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "api.h" +#include "eventloop.h" + +namespace DBus { + +namespace Glib { + +class BusDispatcher; + +class DXXAPI BusTimeout : public Timeout +{ +private: + + BusTimeout( Timeout::Internal*, GMainContext* ); + + ~BusTimeout(); + + void toggle(); + + static gboolean timeout_handler( gpointer ); + + void _enable(); + + void _disable(); + +private: + + GSource* _source; + GMainContext* _ctx; + +friend class BusDispatcher; +}; + +class DXXAPI BusWatch : public Watch +{ +private: + + BusWatch( Watch::Internal*, GMainContext* ); + + ~BusWatch(); + + void toggle(); + + static gboolean watch_handler( gpointer ); + + void _enable(); + + void _disable(); + +private: + + GSource* _source; + GMainContext* _ctx; + +friend class BusDispatcher; +}; + +class DXXAPI BusDispatcher : public Dispatcher +{ +public: + BusDispatcher() : _ctx(NULL) {} + + void attach( GMainContext* ); + + void enter() {} + + void leave() {} + + Timeout* add_timeout( Timeout::Internal* ); + + void rem_timeout( Timeout* ); + + Watch* add_watch( Watch::Internal* ); + + void rem_watch( Watch* ); + +private: + + GMainContext* _ctx; +}; + +} /* namespace Glib */ + +} /* namespace DBus */ + +#endif//__DBUSXX_GLIB_INTEGRATION_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/connection.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/connection.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/connection.h (revision 562) @@ -0,0 +1,126 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_CONNECTION_H +#define __DBUSXX_CONNECTION_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "api.h" +#include "types.h" +#include "util.h" +#include "message.h" +#include "pendingcall.h" + +namespace DBus { + +class Connection; + +typedef Slot MessageSlot; + +typedef std::list ConnectionList; + +class ObjectAdaptor; +class Dispatcher; + +class DXXAPI Connection +{ +public: + + static Connection SystemBus(); + + static Connection SessionBus(); + + static Connection ActivationBus(); + + struct Private; + + typedef std::list PrivatePList; + + Connection( Private* ); + + Connection( const char* address, bool priv = true ); + + Connection( const Connection& c ); + + virtual ~Connection(); + + Dispatcher* setup( Dispatcher* ); + + bool operator == ( const Connection& ) const; + + void add_match( const char* rule ); + + void remove_match( const char* rule ); + + bool add_filter( MessageSlot& ); + + void remove_filter( MessageSlot& ); + + bool unique_name( const char* n ); + + const char* unique_name() const; + + bool register_bus(); + + bool connected() const; + + void disconnect(); + + void exit_on_disconnect( bool exit ); + + void flush(); + + bool send( const Message&, unsigned int* serial = NULL ); + + Message send_blocking( Message& msg, int timeout ); + + PendingCall send_async( Message& msg, int timeout ); + + void request_name( const char* name, int flags = 0 ); + + bool has_name( const char* name ); + + bool start_service( const char* name, unsigned long flags ); + + const std::vector& names(); + +private: + + DXXAPILOCAL void init(); + +private: + + RefPtrI _pvt; + +friend class ObjectAdaptor; // needed in order to register object paths for a connection +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_CONNECTION_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/introspection.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/introspection.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/introspection.h (revision 562) @@ -0,0 +1,90 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_INTROSPECTION_H +#define __DBUSXX_INTROSPECTION_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "interface.h" + +namespace DBus { + +struct DXXAPI IntrospectedArgument +{ + const char* name; + const char* type; + const bool in; +}; + +struct DXXAPI IntrospectedMethod +{ + const char* name; + const IntrospectedArgument* args; +}; + +struct DXXAPI IntrospectedProperty +{ + const char* name; + const char* type; + const bool read; + const bool write; +}; + +struct DXXAPI IntrospectedInterface +{ + const char* name; + const IntrospectedMethod* methods; + const IntrospectedMethod* signals; + const IntrospectedProperty* properties; +}; + +class DXXAPI IntrospectableAdaptor : public InterfaceAdaptor +{ +public: + + IntrospectableAdaptor(); + + Message Introspect( const CallMessage& ); + +protected: + + IntrospectedInterface* const introspect() const; +}; + +class DXXAPI IntrospectableProxy : public InterfaceProxy +{ +public: + + IntrospectableProxy(); + + std::string Introspect(); +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_INTROSPECTION_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/interface.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/interface.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/interface.h (revision 562) @@ -0,0 +1,195 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_INTERFACE_H +#define __DBUSXX_INTERFACE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "api.h" +#include "util.h" +#include "types.h" + +#include "message.h" + +namespace DBus { + +//todo: this should belong to to properties.h +struct DXXAPI PropertyData +{ + bool read; + bool write; + std::string sig; + Variant value; +}; + +typedef std::map PropertyTable; + +class IntrospectedInterface; + +class ObjectAdaptor; +class InterfaceAdaptor; +class SignalMessage; + +typedef std::map InterfaceAdaptorTable; + +class DXXAPI AdaptorBase +{ +public: + + virtual const ObjectAdaptor* object() const = 0 ; + +protected: + + InterfaceAdaptor* find_interface( const std::string& name ); + + virtual ~AdaptorBase() + {} + + virtual void _emit_signal( SignalMessage& ) = 0; + + InterfaceAdaptorTable _interfaces; +}; + +/* +*/ + +class ObjectProxy; +class InterfaceProxy; +class CallMessage; + +typedef std::map InterfaceProxyTable; + +class DXXAPI ProxyBase +{ +public: + + virtual const ObjectProxy* object() const = 0 ; + +protected: + + InterfaceProxy* find_interface( const std::string& name ); + + virtual ~ProxyBase() + {} + + virtual Message _invoke_method( CallMessage& ) = 0; + + InterfaceProxyTable _interfaces; +}; + +class DXXAPI Interface +{ +public: + + Interface( const std::string& name ); + + virtual ~Interface(); + + inline const std::string& name() const; + +private: + + std::string _name; +}; + +/* +*/ + +const std::string& Interface::name() const +{ + return _name; +} + +/* +*/ + +typedef std::map< std::string, Slot > MethodTable; + +class DXXAPI InterfaceAdaptor : public Interface, public virtual AdaptorBase +{ +public: + + InterfaceAdaptor( const std::string& name ); + + Message dispatch_method( const CallMessage& ); + + void emit_signal( const SignalMessage& ); + + Variant* get_property( const std::string& name ); + + void set_property( const std::string& name, Variant& value ); + + virtual IntrospectedInterface* const introspect() const + { + return NULL; + } + +protected: + + MethodTable _methods; + PropertyTable _properties; +}; + +/* +*/ + +typedef std::map< std::string, Slot > SignalTable; + +class DXXAPI InterfaceProxy : public Interface, public virtual ProxyBase +{ +public: + + InterfaceProxy( const std::string& name ); + + Message invoke_method( const CallMessage& ); + + bool dispatch_signal( const SignalMessage& ); + +protected: + + SignalTable _signals; +}; + +# define register_method(interface, method, callback) \ + InterfaceAdaptor::_methods[ #method ] = \ + new ::DBus::Callback< interface, ::DBus::Message, const ::DBus::CallMessage& >(this, & interface :: callback ); + +# define bind_property(variable, type, can_read, can_write) \ + InterfaceAdaptor::_properties[ #variable ].read = can_read; \ + InterfaceAdaptor::_properties[ #variable ].write = can_write; \ + InterfaceAdaptor::_properties[ #variable ].sig = type; \ + variable.bind( InterfaceAdaptor::_properties[ #variable ] ); + +# define connect_signal(interface, signal, callback) \ + InterfaceProxy::_signals[ #signal ] = \ + new ::DBus::Callback< interface, void, const ::DBus::SignalMessage& >(this, & interface :: callback ); + +} /* namespace DBus */ + +#endif//__DBUSXX_INTERFACE_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/types.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/types.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/types.h (revision 562) @@ -0,0 +1,514 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_TYPES_H +#define __DBUSXX_TYPES_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "api.h" +#include "util.h" +#include "message.h" +#include "error.h" + +namespace DBus { + +typedef unsigned char Byte; +typedef bool Bool; +typedef signed short Int16; +typedef unsigned short UInt16; +typedef signed int Int32; +typedef unsigned int UInt32; +typedef signed long long Int64; +typedef unsigned long long UInt64; +typedef double Double; +typedef std::string String; + +struct DXXAPI Path : public std::string +{ + Path() {} + Path( const std::string& s ) : std::string(s) {} + Path( const char* c ) : std::string(c) {} + Path& operator = ( std::string& s ) + { + std::string::operator = (s); + return *this; + } +}; + +struct DXXAPI Signature : public std::string +{ + Signature() {} + Signature( const std::string& s ) : std::string(s) {} + Signature( const char* c ) : std::string(c) {} + Signature& operator = ( std::string& s ) + { + std::string::operator = (s); + return *this; + } +}; + +struct DXXAPI Invalid {}; + +class DXXAPI Variant +{ +public: + + Variant(); + + Variant( MessageIter& it ); + + Variant& operator = ( const Variant& v ); + + const Signature signature() const; + + void clear(); + + MessageIter reader() const + { + return _msg.reader(); + } + + MessageIter writer() + { + return _msg.writer(); + } + + template + operator T() const + { + T cast; + MessageIter ri = _msg.reader(); + ri >> cast; + return cast; + } + +private: + + Message _msg; +}; + +template < + typename T1, + typename T2 = Invalid, + typename T3 = Invalid, + typename T4 = Invalid, + typename T5 = Invalid, + typename T6 = Invalid, + typename T7 = Invalid, + typename T8 = Invalid // who needs more than eight? +> +struct Struct +{ + T1 _1; T2 _2; T3 _3; T4 _4; T5 _5; T6 _6; T7 _7; T8 _8; +}; + +template +inline bool dict_has_key( const std::map& map, const K& key ) +{ + return map.find(key) != map.end(); +} + +template +struct type +{ + static std::string sig() + { + throw ErrorInvalidArgs("unknown type"); + return ""; + } +}; + +template <> struct type { static std::string sig(){ return "v"; } }; +template <> struct type { static std::string sig(){ return "y"; } }; +template <> struct type { static std::string sig(){ return "b"; } }; +template <> struct type { static std::string sig(){ return "n"; } }; +template <> struct type { static std::string sig(){ return "q"; } }; +template <> struct type { static std::string sig(){ return "i"; } }; +template <> struct type { static std::string sig(){ return "u"; } }; +template <> struct type { static std::string sig(){ return "x"; } }; +template <> struct type { static std::string sig(){ return "t"; } }; +template <> struct type { static std::string sig(){ return "d"; } }; +template <> struct type { static std::string sig(){ return "s"; } }; +template <> struct type { static std::string sig(){ return "o"; } }; +template <> struct type { static std::string sig(){ return "g"; } }; +template <> struct type { static std::string sig(){ return ""; } }; + +template +struct type< std::vector > +{ static std::string sig(){ return "a" + type::sig(); } }; + +template +struct type< std::map > +{ static std::string sig(){ return "a{" + type::sig() + type::sig() + "}"; } }; + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8 // who needs more than eight? +> +struct type< Struct > +{ + static std::string sig() + { + return "(" + + type::sig() + + type::sig() + + type::sig() + + type::sig() + + type::sig() + + type::sig() + + type::sig() + + type::sig() + + ")"; + } +}; + +} /* namespace DBus */ + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Invalid& ) +{ + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Byte& val ) +{ + iter.append_byte(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Bool& val ) +{ + iter.append_bool(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Int16& val ) +{ + iter.append_int16(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::UInt16& val ) +{ + iter.append_uint16(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Int32& val ) +{ + iter.append_int32(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::UInt32& val ) +{ + iter.append_uint32(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Int64& val ) +{ + iter.append_int64(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::UInt64& val ) +{ + iter.append_uint64(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Double& val ) +{ + iter.append_double(val); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::String& val ) +{ + iter.append_string(val.c_str()); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Path& val ) +{ + iter.append_path(val.c_str()); + return iter; +} + +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Signature& val ) +{ + iter.append_signature(val.c_str()); + return iter; +} + +template +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const std::vector& val ) +{ + const std::string sig = DBus::type::sig(); + DBus::MessageIter ait = iter.new_array(sig.c_str()); + + typename std::vector::const_iterator vit; + for(vit = val.begin(); vit != val.end(); ++vit) + { + ait << *vit; + } + + iter.close_container(ait); + return iter; +} + +template<> +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const std::vector& val ) +{ + DBus::MessageIter ait = iter.new_array("y"); + ait.append_array('y', &val.front(), val.size()); + iter.close_container(ait); + return iter; +} + +template +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const std::map& val ) +{ + const std::string sig = "{" + DBus::type::sig() + DBus::type::sig() + "}"; + DBus::MessageIter ait = iter.new_array(sig.c_str()); + + typename std::map::const_iterator mit; + for(mit = val.begin(); mit != val.end(); ++mit) + { + DBus::MessageIter eit = ait.new_dict_entry(); + + eit << mit->first << mit->second; + + ait.close_container(eit); + } + + iter.close_container(ait); + return iter; +} + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8 +> +inline DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Struct& val ) +{ +/* const std::string sig = + DBus::type::sig() + DBus::type::sig() + DBus::type::sig() + DBus::type::sig() + + DBus::type::sig() + DBus::type::sig() + DBus::type::sig() + DBus::type::sig(); +*/ + DBus::MessageIter sit = iter.new_struct(/*sig.c_str()*/); + + sit << val._1 << val._2 << val._3 << val._4 << val._5 << val._6 << val._7 << val._8; + + iter.close_container(sit); + + return iter; +} + +extern DXXAPI DBus::MessageIter& operator << ( DBus::MessageIter& iter, const DBus::Variant& val ); + +/* + */ + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Invalid& ) +{ + return iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Byte& val ) +{ + val = iter.get_byte(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Bool& val ) +{ + val = iter.get_bool(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Int16& val ) +{ + val = iter.get_int16(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::UInt16& val ) +{ + val = iter.get_uint16(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Int32& val ) +{ + val = iter.get_int32(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::UInt32& val ) +{ + val = iter.get_uint32(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Int64& val ) +{ + val = iter.get_int64(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::UInt64& val ) +{ + val = iter.get_uint64(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Double& val ) +{ + val = iter.get_double(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::String& val ) +{ + val = iter.get_string(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Path& val ) +{ + val = iter.get_path(); + return ++iter; +} + +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Signature& val ) +{ + val = iter.get_signature(); + return ++iter; +} + +template +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, std::vector& val ) +{ + if(!iter.is_array()) + throw DBus::ErrorInvalidArgs("array expected"); + + DBus::MessageIter ait = iter.recurse(); + + while(!ait.at_end()) + { + E elem; + + ait >> elem; + + val.push_back(elem); + } + return ++iter; +} + +template<> +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, std::vector& val ) +{ + if(!iter.is_array()) + throw DBus::ErrorInvalidArgs("array expected"); + + if(iter.array_type() != 'y') + throw DBus::ErrorInvalidArgs("byte-array expected"); + + DBus::MessageIter ait = iter.recurse(); + + DBus::Byte* array; + size_t length = ait.get_array(&array); + + val.insert(val.end(), array, array+length); + + return ++iter; +} + +template +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, std::map& val ) +{ + if(!iter.is_dict()) + throw DBus::ErrorInvalidArgs("dictionary value expected"); + + DBus::MessageIter mit = iter.recurse(); + + while(!mit.at_end()) + { + K key; V value; + + DBus::MessageIter eit = mit.recurse(); + + eit >> key >> value; + + val[key] = value; + + ++mit; + } + + return ++iter; +} + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8 +> +inline DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Struct& val) +{ + DBus::MessageIter sit = iter.recurse(); + + sit >> val._1 >> val._2 >> val._3 >> val._4 >> val._5 >> val._6 >> val._7 >> val._8; + + return ++iter; +} + +extern DXXAPI DBus::MessageIter& operator >> ( DBus::MessageIter& iter, DBus::Variant& val ); + +#endif//__DBUSXX_TYPES_H + Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/config.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/config.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/config.h (revision 562) @@ -0,0 +1,74 @@ +/* include/dbus-c++/config.h. Generated from config.h.in by configure. */ +/* include/dbus-c++/config.h.in. Generated from configure.ac by autoheader. */ + +/* unstable DBus */ +/* #undef DBUS_API_SUBJECT_TO_CHANGE */ + +/* DBus supports recursive mutexes (needs DBus >= 0.95) */ +#define DBUS_HAS_RECURSIVE_MUTEX + +/* dbus_threads_init_default (needs DBus >= 0.93) */ +#define DBUS_HAS_THREADS_INIT_DEFAULT + +/* to enable hidden symbols */ +#define GCC_HASCLASSVISIBILITY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_EXPAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "libdbus-c++" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "shackan@gmail.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libdbus-c++" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libdbus-c++ 0.5.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libdbus-c--" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.5.0" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.5.0" Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/object.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/object.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/object.h (revision 562) @@ -0,0 +1,223 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_OBJECT_H +#define __DBUSXX_OBJECT_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "api.h" +#include "interface.h" +#include "connection.h" +#include "message.h" +#include "types.h" + +namespace DBus { + +class DXXAPI Object +{ +protected: + + Object( Connection& conn, const Path& path, const char* service ); + +public: + + virtual ~Object(); + + inline const DBus::Path& path() const; + + inline const std::string& service() const; + + inline Connection& conn(); + +private: + + DXXAPILOCAL virtual bool handle_message( const Message& ) = 0; + DXXAPILOCAL virtual void register_obj() = 0; + DXXAPILOCAL virtual void unregister_obj() = 0; + +private: + + Connection _conn; + DBus::Path _path; + std::string _service; +}; + +/* +*/ + +Connection& Object::conn() +{ + return _conn; +} + +const DBus::Path& Object::path() const +{ + return _path; +} + +const std::string& Object::service() const +{ + return _service; +} + +/* +*/ + +class DXXAPI Tag +{ +public: + + virtual ~Tag() + {} +}; + +/* +*/ + +class ObjectAdaptor; + +typedef std::list ObjectAdaptorPList; + +class DXXAPI ObjectAdaptor : public Object, public virtual AdaptorBase +{ +public: + + static ObjectAdaptor* from_path( const Path& path ); + + static ObjectAdaptorPList from_path_prefix( const std::string& prefix ); + + struct Private; + + ObjectAdaptor( Connection& conn, const Path& path ); + + ~ObjectAdaptor(); + + inline const ObjectAdaptor* object() const; + +protected: + + class DXXAPI Continuation + { + public: + + inline MessageIter& writer(); + + inline Tag* tag(); + + private: + + Continuation( Connection& conn, const CallMessage& call, const Tag* tag ); + + Connection _conn; + CallMessage _call; + MessageIter _writer; + ReturnMessage _return; + const Tag* _tag; + + friend class ObjectAdaptor; + }; + + void return_later( const Tag* tag ); + + void return_now( Continuation* ret ); + + void return_error( Continuation* ret, const Error error ); + + Continuation* find_continuation( const Tag* tag ); + +private: + + void _emit_signal( SignalMessage& ); + + bool handle_message( const Message& ); + + void register_obj(); + void unregister_obj(); + + typedef std::map ContinuationMap; + ContinuationMap _continuations; + +friend struct Private; +}; + +const ObjectAdaptor* ObjectAdaptor::object() const +{ + return this; +} + +Tag* ObjectAdaptor::Continuation::tag() +{ + return const_cast(_tag); +} + +MessageIter& ObjectAdaptor::Continuation::writer() +{ + return _writer; +} + +/* +*/ + +class ObjectProxy; + +typedef std::list ObjectProxyPList; + +class DXXAPI ObjectProxy : public Object, public virtual ProxyBase +{ +public: + + ObjectProxy( Connection& conn, const Path& path, const char* service = "" ); + + ~ObjectProxy(); + + inline const ObjectProxy* object() const; + +private: + + Message _invoke_method( CallMessage& ); + + bool handle_message( const Message& ); + + void register_obj(); + void unregister_obj(); + +private: + + MessageSlot _filtered; +}; + +const ObjectProxy* ObjectProxy::object() const +{ + return this; +} + +} /* namespace DBus */ + +#endif//__DBUSXX_OBJECT_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/server.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/server.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/server.h (revision 562) @@ -0,0 +1,78 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_SERVER_H +#define __DBUSXX_SERVER_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "api.h" +#include "error.h" +#include "connection.h" +#include "util.h" +#include "dispatcher.h" + +namespace DBus { + +class Server; + +typedef std::list ServerList; + +class DXXAPI Server +{ +public: + + Server( const char* address ); + + Dispatcher* setup( Dispatcher* ); + + virtual ~Server(); + + bool listening() const; + + bool operator == ( const Server& ) const; + + void disconnect(); + + struct Private; + +protected: + + Server( const Server& s ) + {} + + virtual void on_new_connection( Connection& c ) = 0; + +private: + + RefPtrI _pvt; +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_SERVER_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/api.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/api.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/api.h (revision 562) @@ -0,0 +1,42 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_API_H +#define __DBUSXX_API_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef GCC_HASCLASSVISIBILITY +# define DXXAPILOCAL __attribute__ ((visibility("hidden"))) +# define DXXAPIPUBLIC __attribute__ ((visibility("default"))) +#else +# define DXXAPILOCAL +# define DXXAPIPUBLIC +#endif + +#define DXXAPI DXXAPIPUBLIC + +#endif//__DBUSXX_API_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/eventloop.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/eventloop.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/eventloop.h (revision 562) @@ -0,0 +1,202 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_EVENTLOOP_H +#define __DBUSXX_EVENTLOOP_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "api.h" +#include "dispatcher.h" +#include "util.h" + +namespace DBus { + +class EepleMainLoop; + +class DXXAPI EepleTimeout +{ +public: + + EepleTimeout( int interval, bool repeat, EepleMainLoop* ); + + virtual ~EepleTimeout(); + + bool enabled(){ return _enabled; } + void enabled(bool e){ _enabled = e; } + + int interval(){ return _interval; } + void interval(int i){ _interval = i; } + + bool repeat(){ return _repeat; } + void repeat(bool r){ _repeat = r; } + + void* data(){ return _data; } + void data(void* d){ _data = d; } + + Slot expired; + +private: + + bool _enabled; + + int _interval; + bool _repeat; + + double _expiration; + + void* _data; + + EepleMainLoop* _disp; + +friend class EepleMainLoop; +}; + +typedef std::list< EepleTimeout* > Timeouts; + +class DXXAPI EepleWatch +{ +public: + + EepleWatch( int fd, int flags, EepleMainLoop* ); + + virtual ~EepleWatch(); + + bool enabled(){ return _enabled; } + void enabled(bool e){ _enabled = e; } + + int descriptor(){ return _fd; } + + int flags(){ return _flags; } + void flags( int f ){ _flags = f; } + + int state(){ return _state; } + + void* data(){ return _data; } + void data(void* d){ _data = d; } + + Slot ready; + +private: + + bool _enabled; + + int _fd; + int _flags; + int _state; + + void* _data; + + EepleMainLoop* _disp; + +friend class EepleMainLoop; +}; + +typedef std::list< EepleWatch* > Watches; + +class DXXAPI EepleMainLoop +{ +public: + + EepleMainLoop(); + + virtual ~EepleMainLoop(); + + virtual void dispatch(); + +private: + + Timeouts _timeouts; + Watches _watches; + +friend class EepleTimeout; +friend class EepleWatch; +}; + +/* the classes below are those you are going to implement if you + * want to use another event loop (Qt, Glib, boost, whatever). + * + * Don't forget to set 'default_dispatcher' accordingly! + */ + +class BusDispatcher; + +class DXXAPI BusTimeout : public Timeout, public EepleTimeout +{ + BusTimeout( Timeout::Internal*, BusDispatcher* ); + + void toggle(); + +friend class BusDispatcher; +}; + +class DXXAPI BusWatch : public Watch, public EepleWatch +{ + BusWatch( Watch::Internal*, BusDispatcher* ); + + void toggle(); + +friend class BusDispatcher; +}; + +class DXXAPI BusDispatcher : public Dispatcher, public EepleMainLoop +{ +public: + + BusDispatcher() : _running(false) + {} + + ~BusDispatcher() + {} + + virtual void enter(); + + virtual void leave(); + + virtual void do_iteration(); + + virtual Timeout* add_timeout( Timeout::Internal* ); + + virtual void rem_timeout( Timeout* ); + + virtual Watch* add_watch( Watch::Internal* ); + + virtual void rem_watch( Watch* ); + + void watch_ready( EepleWatch& ); + + void timeout_expired( EepleTimeout& ); + +private: + + bool _running; +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_EVENTLOOP_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/util.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/util.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/util.h (revision 562) @@ -0,0 +1,277 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_UTIL_H +#define __DBUSXX_UTIL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "debug.h" + +namespace DBus { + +/* + * Very simple reference counting + */ + +class DXXAPI RefCnt +{ +public: + + RefCnt() + { + __ref = new int; + (*__ref) = 1; + } + + RefCnt( const RefCnt& rc ) + { + __ref = rc.__ref; + ref(); + } + + virtual ~RefCnt() + { + unref(); + } + + RefCnt& operator = ( const RefCnt& ref ) + { + ref.ref(); + unref(); + __ref = ref.__ref; + return *this; + } + + bool noref() const + { + return (*__ref) == 0; + } + + bool one() const + { + return (*__ref) == 1; + } + +private: + + DXXAPILOCAL void ref() const + { + ++ (*__ref); + } + DXXAPILOCAL void unref() const + { + -- (*__ref); + + if( (*__ref) < 0 ) + { + debug_log("%p: refcount dropped below zero!", __ref); + } + + if( noref() ) + { + delete __ref; + } + } + +private: + + int *__ref; +}; + +/* + * Reference counting pointers (emulate boost::shared_ptr) + */ + +template +class RefPtrI // RefPtr to incomplete type +{ +public: + + RefPtrI( T* ptr = 0 ); + + ~RefPtrI(); + + RefPtrI& operator = ( const RefPtrI& ref ) + { + if( this != &ref ) + { + if(__cnt.one()) delete __ptr; + + __ptr = ref.__ptr; + __cnt = ref.__cnt; + } + return *this; + } + + T& operator *() const + { + return *__ptr; + } + + T* operator ->() const + { + if(__cnt.noref()) return 0; + + return __ptr; + } + + T* get() const + { + if(__cnt.noref()) return 0; + + return __ptr; + } + +private: + + T* __ptr; + RefCnt __cnt; +}; + +template +class RefPtr +{ +public: + + RefPtr( T* ptr = 0) + : __ptr(ptr) + {} + + ~RefPtr() + { + if(__cnt.one()) delete __ptr; + } + + RefPtr& operator = ( const RefPtr& ref ) + { + if( this != &ref ) + { + if(__cnt.one()) delete __ptr; + + __ptr = ref.__ptr; + __cnt = ref.__cnt; + } + return *this; + } + + T& operator *() const + { + return *__ptr; + } + + T* operator ->() const + { + if(__cnt.noref()) return 0; + + return __ptr; + } + + T* get() const + { + if(__cnt.noref()) return 0; + + return __ptr; + } + +private: + + T* __ptr; + RefCnt __cnt; +}; + +/* + * Typed callback template + */ + +template +class Callback_Base +{ +public: + + virtual R call( P param ) const = 0; + + virtual ~Callback_Base() + {} +}; + +template +class Slot +{ +public: + + Slot& operator = ( Callback_Base* s ) + { + _cb = s; + + return *this; + } + + R operator()( P param ) const + { + /*if(_cb.get())*/ return _cb->call(param); + } + + R call( P param ) const + { + /*if(_cb.get())*/ return _cb->call(param); + } + + bool empty() + { + return _cb.get() == 0; + } + +private: + + RefPtr< Callback_Base > _cb; +}; + +template +class Callback : public Callback_Base +{ +public: + + typedef R (C::*M)(P); + + Callback( C* c, M m ) + : _c(c), _m(m) + {} + + R call( P param ) const + { + /*if(_c)*/ return (_c->*_m)(param); + } + +private: + + C* _c; M _m; +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_UTIL_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/pendingcall.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/pendingcall.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/pendingcall.h (revision 562) @@ -0,0 +1,75 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_PENDING_CALL_H +#define __DBUSXX_PENDING_CALL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "util.h" + +namespace DBus { + +class Connection; + +class DXXAPI PendingCall +{ +public: + + struct Private; + + PendingCall( Private* ); + + virtual ~PendingCall(); + + bool completed(); + + void cancel(); + + void block(); + + void data( void* ); + + void* data(); + + Slot slot; + +private: + + DXXAPILOCAL PendingCall( const PendingCall& ); + +private: + + RefPtrI _pvt; + +friend struct Private; +friend class Connection; +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_PENDING_CALL_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/refptr_impl.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/refptr_impl.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/refptr_impl.h (revision 562) @@ -0,0 +1,50 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_REFPTR_IMPL_H +#define __DBUSXX_REFPTR_IMPL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "util.h" + +namespace DBus { + +template +RefPtrI::RefPtrI( T* ptr ) +: __ptr(ptr) +{} + +template +RefPtrI::~RefPtrI() +{ + if(__cnt.one()) delete __ptr; +} + +} /* namespace DBus */ + +#endif//__DBUSXX_REFPTR_IMPL_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/property.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/property.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/property.h (revision 562) @@ -0,0 +1,106 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_PROPERTY_H +#define __DBUSXX_PROPERTY_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "types.h" +#include "interface.h" + +namespace DBus { + +template +class PropertyAdaptor +{ +public: + + PropertyAdaptor() : _data(0) + {} + + void bind( PropertyData& data ) + { + _data = &data; + } + + T operator() (void) const + { + return (T)_data->value; + } + + PropertyAdaptor& operator = ( const T& t ) + { + _data->value.clear(); + MessageIter wi = _data->value.writer(); + wi << t; + return *this; + } + +private: + + PropertyData* _data; +}; + +struct IntrospectedInterface; + +class DXXAPI PropertiesAdaptor : public InterfaceAdaptor +{ +public: + + PropertiesAdaptor(); + + Message Get( const CallMessage& ); + + Message Set( const CallMessage& ); + +protected: + + virtual void on_get_property( InterfaceAdaptor& interface, const String& property, Variant& value ) + {} + + virtual void on_set_property( InterfaceAdaptor& interface, const String& property, const Variant& value ) + {} + + IntrospectedInterface* const introspect() const; +}; + +class DXXAPI PropertiesProxy : public InterfaceProxy +{ +public: + + PropertiesProxy(); + + Variant Get( const String& interface, const String& property ); + + void Set( const String& interface, const String& property, const Variant& value ); +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_PROPERTY_H + Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/message.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/message.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/message.h (revision 562) @@ -0,0 +1,312 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_MESSAGE_H +#define __DBUSXX_MESSAGE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "api.h" +#include "util.h" + +namespace DBus { + +class Message; +class ErrorMessage; +class SignalMessage; +class ReturnMessage; +class Error; +class Connection; + +class DXXAPI MessageIter +{ +public: + + MessageIter() {} + + int type(); + + bool at_end(); + + bool has_next(); + + MessageIter& operator ++(); + + MessageIter operator ++(int); + + bool append_byte( unsigned char byte ); + + unsigned char get_byte(); + + bool append_bool( bool b ); + + bool get_bool(); + + bool append_int16( signed short i ); + + signed short get_int16(); + + bool append_uint16( unsigned short u ); + + unsigned short get_uint16(); + + bool append_int32( signed int i ); + + signed int get_int32(); + + bool append_uint32( unsigned int u ); + + unsigned int get_uint32(); + + bool append_int64( signed long long i ); + + signed long long get_int64(); + + bool append_uint64( unsigned long long i ); + + unsigned long long get_uint64(); + + bool append_double( double d ); + + double get_double(); + + bool append_string( const char* chars ); + + const char* get_string(); + + bool append_path( const char* chars ); + + const char* get_path(); + + bool append_signature( const char* chars ); + + const char* get_signature(); + + char* signature() const; //returned string must be manually free()'d + + MessageIter recurse(); + + bool append_array( char type, const void* ptr, size_t length ); + + int array_type(); + + int get_array( void* ptr ); + + bool is_array(); + + bool is_dict(); + + MessageIter new_array( const char* sig ); + + MessageIter new_variant( const char* sig ); + + MessageIter new_struct(); + + MessageIter new_dict_entry(); + + void close_container( MessageIter& container ); + + void copy_data( MessageIter& to ); + + Message& msg() const + { + return *_msg; + } + +private: + + DXXAPILOCAL MessageIter(Message& msg) : _msg(&msg) {} + + DXXAPILOCAL bool append_basic( int type_id, void* value ); + + DXXAPILOCAL void get_basic( int type_id, void* ptr ); + +private: + + /* I'm sorry, but don't want to include dbus.h in the public api + */ + unsigned char _iter[sizeof(void*)*3+sizeof(int)*11]; + + Message* _msg; + +friend class Message; +}; + +class DXXAPI Message +{ +public: + + struct Private; + + Message( Private*, bool incref = true ); + + Message( const Message& m ); + + ~Message(); + + Message& operator = ( const Message& m ); + + Message copy(); + + int type() const; + + int serial() const; + + int reply_serial() const; + + bool reply_serial( int ); + + const char* sender() const; + + bool sender( const char* s ); + + const char* destination() const; + + bool destination( const char* s ); + + bool is_error() const; + + bool is_signal( const char* interface, const char* member ) const; + + MessageIter reader() const; + + MessageIter writer(); + + bool append( int first_type, ... ); + + void terminate(); + +protected: + + Message(); + +protected: + + RefPtrI _pvt; + +/* classes who need to read `_pvt` directly +*/ +friend class ErrorMessage; +friend class ReturnMessage; +friend class MessageIter; +friend class Error; +friend class Connection; +}; + +/* +*/ + +class DXXAPI ErrorMessage : public Message +{ +public: + + ErrorMessage(); + + ErrorMessage( const Message&, const char* name, const char* message ); + + const char* name() const; + + bool name( const char* n ); + + bool operator == ( const ErrorMessage& ) const; +}; + +/* +*/ + +class DXXAPI SignalMessage : public Message +{ +public: + + SignalMessage( const char* name ); + + SignalMessage( const char* path, const char* interface, const char* name ); + + const char* interface() const; + + bool interface( const char* i ); + + const char* member() const; + + bool member( const char* m ); + + const char* path() const; + + char** path_split() const; + + bool path( const char* p ); + + bool operator == ( const SignalMessage& ) const; +}; + +/* +*/ + +class DXXAPI CallMessage : public Message +{ +public: + + CallMessage(); + + CallMessage( const char* dest, const char* path, const char* iface, const char* method ); + + const char* interface() const; + + bool interface( const char* i ); + + const char* member() const; + + bool member( const char* m ); + + const char* path() const; + + char** path_split() const; + + bool path( const char* p ); + + const char* signature() const; + + bool operator == ( const CallMessage& ) const; +}; + +/* +*/ + +class DXXAPI ReturnMessage : public Message +{ +public: + + ReturnMessage( const CallMessage& callee ); + + const char* signature() const; +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_MESSAGE_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/dispatcher.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/dispatcher.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/dispatcher.h (revision 562) @@ -0,0 +1,258 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_DISPATCHER_H +#define __DBUSXX_DISPATCHER_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" +#include "connection.h" + +namespace DBus { + +class DXXAPI Timeout +{ +public: + + class Internal; + + Timeout( Internal* i ); + + virtual ~Timeout(){} + + int interval() const; + + bool enabled() const; + + bool handle(); + + virtual void toggle() = 0; + +private: + + DXXAPILOCAL Timeout( const Timeout& ); + +private: + + Internal* _int; +}; + +class DXXAPI Watch +{ +public: + + class Internal; + + Watch( Internal* i ); + + virtual ~Watch(){} + + int descriptor() const; + + int flags() const; + + bool enabled() const; + + bool handle( int flags ); + + virtual void toggle() = 0; + +private: + + DXXAPILOCAL Watch( const Watch& ); + +private: + + Internal* _int; +}; + +class DXXAPI Dispatcher +{ +public: + + virtual ~Dispatcher() + {} + + void queue_connection( Connection::Private* ); + + void dispatch_pending(); + + virtual void enter() = 0; + + virtual void leave() = 0; + + virtual Timeout* add_timeout( Timeout::Internal* ) = 0; + + virtual void rem_timeout( Timeout* ) = 0; + + virtual Watch* add_watch( Watch::Internal* ) = 0; + + virtual void rem_watch( Watch* ) = 0; + + struct Private; + +private: + + Connection::PrivatePList _pending_queue; +}; + +extern DXXAPI Dispatcher* default_dispatcher; + +/* classes for multithreading support +*/ + +class DXXAPI Mutex +{ +public: + + virtual ~Mutex() {} + + virtual void lock() = 0; + + virtual void unlock() = 0; + + struct Internal; + +protected: + + Internal* _int; +}; + +class DXXAPI CondVar +{ +public: + + virtual ~CondVar() {} + + virtual void wait( Mutex* ) = 0; + + virtual bool wait_timeout( Mutex*, int timeout ) = 0; + + virtual void wake_one() = 0; + + virtual void wake_all() = 0; + + struct Internal; + +protected: + + Internal* _int; +}; + +#ifndef DBUS_HAS_RECURSIVE_MUTEX +typedef Mutex* (*MutexNewFn)(); +typedef bool (*MutexFreeFn)( Mutex* mx ); +typedef bool (*MutexLockFn)( Mutex* mx ); +typedef void (*MutexUnlockFn)( Mutex* mx ); +#else +typedef Mutex* (*MutexNewFn)(); +typedef void (*MutexFreeFn)( Mutex* mx ); +typedef void (*MutexLockFn)( Mutex* mx ); +typedef void (*MutexUnlockFn)( Mutex* mx ); +#endif//DBUS_HAS_RECURSIVE_MUTEX + +typedef CondVar* (*CondVarNewFn)(); +typedef void (*CondVarFreeFn)( CondVar* cv ); +typedef void (*CondVarWaitFn)( CondVar* cv, Mutex* mx ); +typedef bool (*CondVarWaitTimeoutFn)( CondVar* cv, Mutex* mx, int timeout ); +typedef void (*CondVarWakeOneFn)( CondVar* cv ); +typedef void (*CondVarWakeAllFn)( CondVar* cv ); + +#ifdef DBUS_HAS_THREADS_INIT_DEFAULT +void DXXAPI _init_threading(); +#endif//DBUS_HAS_THREADS_INIT_DEFAULT + +void DXXAPI _init_threading( + MutexNewFn, MutexFreeFn, MutexLockFn, MutexUnlockFn, + CondVarNewFn, CondVarFreeFn, CondVarWaitFn, CondVarWaitTimeoutFn, CondVarWakeOneFn, CondVarWakeAllFn +); + +template +struct Threading +{ + static void init() + { + _init_threading( + mutex_new, mutex_free, mutex_lock, mutex_unlock, + condvar_new, condvar_free, condvar_wait, condvar_wait_timeout, condvar_wake_one, condvar_wake_all + ); + } + + static Mutex* mutex_new() + { + return new Mx; + } + + static void mutex_free( Mutex* mx ) + { + delete mx; + } + + static void mutex_lock( Mutex* mx ) + { + mx->lock(); + } + + static void mutex_unlock( Mutex* mx ) + { + mx->unlock(); + } + + static CondVar* condvar_new() + { + return new Cv; + } + + static void condvar_free( CondVar* cv ) + { + delete cv; + } + + static void condvar_wait( CondVar* cv, Mutex* mx ) + { + cv->wait(mx); + } + + static bool condvar_wait_timeout( CondVar* cv, Mutex* mx, int timeout ) + { + return cv->wait_timeout(mx, timeout); + } + + static void condvar_wake_one( CondVar* cv ) + { + cv->wake_one(); + } + + static void condvar_wake_all( CondVar* cv ) + { + cv->wake_all(); + } +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_DISPATCHER_H Index: /tags/2.0-rc2/external/dbus/include/dbus-c++/debug.h =================================================================== --- /tags/2.0-rc2/external/dbus/include/dbus-c++/debug.h (revision 562) +++ /tags/2.0-rc2/external/dbus/include/dbus-c++/debug.h (revision 562) @@ -0,0 +1,42 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_DEBUG_H +#define __DBUSXX_DEBUG_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "api.h" + +namespace DBus { + +typedef void (*LogFunction)(const char* format, ...); + +extern DXXAPI LogFunction debug_log; + +} /* namespace DBus */ + +#endif Index: /tags/2.0-rc2/external/dbus/SConscript =================================================================== --- /tags/2.0-rc2/external/dbus/SConscript (revision 1185) +++ /tags/2.0-rc2/external/dbus/SConscript (revision 1185) @@ -0,0 +1,82 @@ +# +# Copyright (C) 2007 Arnold Krille +# Copyright (C) 2007 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 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 . +# + +import os +import sys + +Import( 'env' ) +dbus_env = env.Clone() + +if dbus_env.has_key('DBUS1_FLAGS'): + dbus_env.MergeFlags( dbus_env['DBUS1_FLAGS'] ) + +# add the local version of libdbus++ +dbus_env.AppendUnique( CPPPATH=["#/external/dbus/include"] ) +dbus_env.AppendUnique( LIBPATH=[dbus_env['build_base']+"external/dbus"]) +dbus_env.AppendUnique( LIBS=["dbus-c++"] ) +dbus_env.AppendUnique( CCFLAGS=["-DDBUS_API_SUBJECT_TO_CHANGE"] ) + +sources = [ + 'src/connection.cpp', + 'src/debug.cpp', + 'src/dispatcher.cpp', + 'src/error.cpp', + 'src/eventloop.cpp', + 'src/interface.cpp', + 'src/introspection.cpp', + 'src/property.cpp', + 'src/message.cpp', + 'src/object.cpp', + 'src/pendingcall.cpp', + 'src/server.cpp', + 'src/types.cpp' +] + +if dbus_env.has_key('DEBUG') and dbus_env['DEBUG']: + dbus_env.AppendUnique( CCFLAGS=["-DDEBUG","-g"] ) + +dbus_env.PrependUnique( LIBS=["expat"] ) +libdbuspp=dbus_env.StaticLibrary('dbus-c++', sources) + +# +# tools +# + +tools_env = dbus_env + +introspect_sources = [ + 'tools/introspect.cpp', +] + +xml2cpp_sources = [ + 'tools/xml.cpp','tools/xml2cpp.cpp' +] + +tools_env.AppendUnique( CCFLAGS=["-DDBUS_API_SUBJECT_TO_CHANGE"] ) +tools_env.AppendUnique( CPPPATH=["#/external/dbus/include"] ) +tools_env.PrependUnique( LIBPATH=dbus_env['build_base']+"external/dbus" ) +tools_env.PrependUnique( LIBS="dbus-c++" ) + +dbusxx_introspect = tools_env.Program('dbusxx-introspect', introspect_sources) +dbusxx_xml2cpp = tools_env.Program('dbusxx-xml2cpp', xml2cpp_sources) + Index: /tags/2.0-rc2/external/dbus/src/glib-integration.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/glib-integration.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/glib-integration.cpp (revision 562) @@ -0,0 +1,218 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include + +#include // for DBUS_WATCH_* + +using namespace DBus; + +Glib::BusTimeout::BusTimeout( Timeout::Internal* ti, GMainContext* ctx ) +: Timeout(ti), _ctx(ctx) +{ + _enable(); +} + +Glib::BusTimeout::~BusTimeout() +{ + _disable(); +} + +void Glib::BusTimeout::toggle() +{ + debug_log("glib: timeout %p toggled (%s)", this, Timeout::enabled() ? "on":"off"); + + if(Timeout::enabled()) _enable(); + else _disable(); +} + +gboolean Glib::BusTimeout::timeout_handler( gpointer data ) +{ + Glib::BusTimeout* t = reinterpret_cast(data); + + t->handle(); + + return TRUE; +} + +void Glib::BusTimeout::_enable() +{ + _source = g_timeout_source_new(Timeout::interval()); + g_source_set_callback(_source, timeout_handler, this, NULL); + g_source_attach(_source, _ctx); +} + +void Glib::BusTimeout::_disable() +{ + g_source_destroy(_source); +} + +struct BusSource +{ + GSource source; + GPollFD poll; +}; + +static gboolean watch_prepare( GSource *source, gint *timeout ) +{ +// debug_log("glib: watch_prepare"); + + *timeout = -1; + return FALSE; +} + +static gboolean watch_check( GSource *source ) +{ +// debug_log("glib: watch_check"); + + BusSource* io = (BusSource*)source; + return io->poll.revents ? TRUE : FALSE; +} + +static gboolean watch_dispatch( GSource *source, GSourceFunc callback, gpointer data ) +{ + debug_log("glib: watch_dispatch"); + + gboolean cb = callback(data); + DBus::default_dispatcher->dispatch_pending(); //TODO: won't work in case of multiple dispatchers + return cb; +} + +static GSourceFuncs watch_funcs = { + watch_prepare, + watch_check, + watch_dispatch, + NULL +}; + +Glib::BusWatch::BusWatch( Watch::Internal* wi, GMainContext* ctx ) +: Watch(wi), _ctx(ctx) +{ + _enable(); +} + +Glib::BusWatch::~BusWatch() +{ + _disable(); +} + +void Glib::BusWatch::toggle() +{ + debug_log("glib: watch %p toggled (%s)", this, Watch::enabled() ? "on":"off"); + + if(Watch::enabled()) _enable(); + else _disable(); +} + +gboolean Glib::BusWatch::watch_handler( gpointer data ) +{ + Glib::BusWatch* w = reinterpret_cast(data); + + BusSource* io = (BusSource*)(w->_source); + + int flags = 0; + if(io->poll.revents & G_IO_IN) + flags |= DBUS_WATCH_READABLE; + if(io->poll.revents & G_IO_OUT) + flags |= DBUS_WATCH_WRITABLE; + if(io->poll.revents & G_IO_ERR) + flags |= DBUS_WATCH_ERROR; + if(io->poll.revents & G_IO_HUP) + flags |= DBUS_WATCH_HANGUP; + + w->handle(flags); + + return TRUE; +} + +void Glib::BusWatch::_enable() +{ + _source = g_source_new(&watch_funcs, sizeof(BusSource)); + g_source_set_callback(_source, watch_handler, this, NULL); + + int flags = Watch::flags(); + int condition = 0; + + if(flags & DBUS_WATCH_READABLE) + condition |= G_IO_IN; +// if(flags & DBUS_WATCH_WRITABLE) +// condition |= G_IO_OUT; + if(flags & DBUS_WATCH_ERROR) + condition |= G_IO_ERR; + if(flags & DBUS_WATCH_HANGUP) + condition |= G_IO_HUP; + + GPollFD* poll = &(((BusSource*)_source)->poll); + poll->fd = Watch::descriptor(); + poll->events = condition; + poll->revents = 0; + + g_source_add_poll(_source, poll); + g_source_attach(_source, _ctx); +} + +void Glib::BusWatch::_disable() +{ + GPollFD* poll = &(((BusSource*)_source)->poll); + g_source_remove_poll(_source, poll); + g_source_destroy(_source); +} + +void Glib::BusDispatcher::attach( GMainContext* ctx ) +{ + _ctx = ctx ? ctx : g_main_context_default(); +} + +Timeout* Glib::BusDispatcher::add_timeout( Timeout::Internal* wi ) +{ + Timeout* t = new Glib::BusTimeout(wi, _ctx); + + debug_log("glib: added timeout %p (%s)", t, t->enabled() ? "on":"off"); + + return t; +} + +void Glib::BusDispatcher::rem_timeout( Timeout* t ) +{ + debug_log("glib: removed timeout %p", t); + + delete t; +} + +Watch* Glib::BusDispatcher::add_watch( Watch::Internal* wi ) +{ + Watch* w = new Glib::BusWatch(wi, _ctx); + + debug_log("glib: added watch %p (%s) fd=%d flags=%d", + w, w->enabled() ? "on":"off", w->descriptor(), w->flags() + ); + return w; +} + +void Glib::BusDispatcher::rem_watch( Watch* w ) +{ + debug_log("glib: removed watch %p", w); + + delete w; +} Index: /tags/2.0-rc2/external/dbus/src/connection.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/connection.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/connection.cpp (revision 562) @@ -0,0 +1,413 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include + +#include +#include + +#include "internalerror.h" + +#include "connection_p.h" +#include "dispatcher_p.h" +#include "server_p.h" +#include "message_p.h" +#include "pendingcall_p.h" + +using namespace DBus; + +Connection::Private::Private( DBusConnection* c, Server::Private* s ) +: conn(c) , dispatcher(0), server(s) +{ + init(); +} + +Connection::Private::Private( DBusBusType type ) +{ + InternalError e; + + conn = dbus_bus_get_private(type, e); + + if(e) throw Error(e); + + init(); +} + +Connection::Private::~Private() +{ + debug_log("terminating connection 0x%08x", conn); + + detach_server(); + + if(dbus_connection_get_is_connected(conn)) + { + std::vector::iterator i = names.begin(); + + while(i != names.end()) + { + debug_log("%s: releasing bus name %s", dbus_bus_get_unique_name(conn), i->c_str()); + dbus_bus_release_name(conn, i->c_str(), NULL); + ++i; + } + dbus_connection_close(conn); + } + dbus_connection_unref(conn); +} + +void Connection::Private::init() +{ + dbus_connection_ref(conn); + dbus_connection_ref(conn); //todo: the library has to own another reference + + disconn_filter = new Callback( + this, &Connection::Private::disconn_filter_function + ); + + dbus_connection_add_filter(conn, message_filter_stub, &disconn_filter, NULL); + + dbus_connection_set_dispatch_status_function(conn, dispatch_status_stub, this, 0); + dbus_connection_set_exit_on_disconnect(conn, false); //why was this set to true?? +} + +void Connection::Private::detach_server() +{ +/* Server::Private* tmp = server; + + server = NULL; + + if(tmp) + { + ConnectionList::iterator i; + + for(i = tmp->connections.begin(); i != tmp->connections.end(); ++i) + { + if(i->_pvt.get() == this) + { + tmp->connections.erase(i); + break; + } + } + }*/ +} + +bool Connection::Private::do_dispatch() +{ + debug_log("dispatching on %p", conn); + + if(!dbus_connection_get_is_connected(conn)) + { + debug_log("connection terminated"); + + detach_server(); + + return true; + } + + return dbus_connection_dispatch(conn) != DBUS_DISPATCH_DATA_REMAINS; +} + +void Connection::Private::dispatch_status_stub( DBusConnection* dc, DBusDispatchStatus status, void* data ) +{ + Private* p = static_cast(data); + + switch(status) + { + case DBUS_DISPATCH_DATA_REMAINS: + debug_log("some dispatching to do on %p", dc); + p->dispatcher->queue_connection(p); + break; + + case DBUS_DISPATCH_COMPLETE: + debug_log("all dispatching done on %p", dc); + break; + + case DBUS_DISPATCH_NEED_MEMORY: //uh oh... + debug_log("connection %p needs memory", dc); + break; + } +} + +DBusHandlerResult Connection::Private::message_filter_stub( DBusConnection* conn, DBusMessage* dmsg, void* data ) +{ + MessageSlot* slot = static_cast(data); + + Message msg = Message(new Message::Private(dmsg)); + + return slot && !slot->empty() && slot->call(msg) + ? DBUS_HANDLER_RESULT_HANDLED + : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +bool Connection::Private::disconn_filter_function( const Message& msg ) +{ + if(msg.is_signal(DBUS_INTERFACE_LOCAL,"Disconnected")) + { + debug_log("%p disconnected by local bus", conn); + dbus_connection_close(conn); + + return true; + } + return false; +} + +Connection Connection::SystemBus() +{ + return Connection(new Private(DBUS_BUS_SYSTEM)); +} + +Connection Connection::SessionBus() +{ + return Connection(new Private(DBUS_BUS_SESSION)); +} + +Connection Connection::ActivationBus() +{ + return Connection(new Private(DBUS_BUS_STARTER)); +} + +Connection::Connection( const char* address, bool priv ) +{ + InternalError e; + DBusConnection* conn = priv + ? dbus_connection_open_private(address, e) + : dbus_connection_open(address, e); + + if(e) throw Error(e); + + _pvt = new Private(conn); + + setup(default_dispatcher); + + debug_log("connected to %s", address); +} + +Connection::Connection( Connection::Private* p ) +: _pvt(p) +{ + setup(default_dispatcher); +} + +Connection::Connection( const Connection& c ) +: _pvt(c._pvt) +{ + dbus_connection_ref(_pvt->conn); +} + +Connection::~Connection() +{ + dbus_connection_unref(_pvt->conn); +} + +Dispatcher* Connection::setup( Dispatcher* dispatcher ) +{ + debug_log("registering stubs for connection %p", _pvt->conn); + + if(!dispatcher) dispatcher = default_dispatcher; + + if(!dispatcher) throw ErrorFailed("no default dispatcher set for new connection"); + + Dispatcher* prev = _pvt->dispatcher; + + _pvt->dispatcher = dispatcher; + + dispatcher->queue_connection(_pvt.get()); + + dbus_connection_set_watch_functions( + _pvt->conn, + Dispatcher::Private::on_add_watch, + Dispatcher::Private::on_rem_watch, + Dispatcher::Private::on_toggle_watch, + dispatcher, + 0 + ); + + dbus_connection_set_timeout_functions( + _pvt->conn, + Dispatcher::Private::on_add_timeout, + Dispatcher::Private::on_rem_timeout, + Dispatcher::Private::on_toggle_timeout, + dispatcher, + 0 + ); + + return prev; +} + +bool Connection::operator == ( const Connection& c ) const +{ + return _pvt->conn == c._pvt->conn; +} + +bool Connection::register_bus() +{ + InternalError e; + + bool r = dbus_bus_register(_pvt->conn, e); + + if(e) throw (e); + + return r; +} + +bool Connection::connected() const +{ + return dbus_connection_get_is_connected(_pvt->conn); +} + +void Connection::disconnect() +{ +// dbus_connection_disconnect(_pvt->conn); // disappeared in 0.9x + dbus_connection_close(_pvt->conn); +} + +void Connection::exit_on_disconnect( bool exit ) +{ + dbus_connection_set_exit_on_disconnect(_pvt->conn, exit); +} + +bool Connection::unique_name( const char* n ) +{ + return dbus_bus_set_unique_name(_pvt->conn, n); +} + +const char* Connection::unique_name() const +{ + return dbus_bus_get_unique_name(_pvt->conn); +} + +void Connection::flush() +{ + dbus_connection_flush(_pvt->conn); +} + +void Connection::add_match( const char* rule ) +{ + InternalError e; + + dbus_bus_add_match(_pvt->conn, rule, e); + + debug_log("%s: added match rule %s", unique_name(), rule); + + if(e) throw Error(e); +} + +void Connection::remove_match( const char* rule ) +{ + InternalError e; + + dbus_bus_remove_match(_pvt->conn, rule, e); + + debug_log("%s: removed match rule %s", unique_name(), rule); + + if(e) throw Error(e); +} + +bool Connection::add_filter( MessageSlot& s ) +{ + debug_log("%s: adding filter", unique_name()); + return dbus_connection_add_filter(_pvt->conn, Private::message_filter_stub, &s, NULL); +} + +void Connection::remove_filter( MessageSlot& s ) +{ + debug_log("%s: removing filter", unique_name()); + dbus_connection_remove_filter(_pvt->conn, Private::message_filter_stub, &s); +} + +bool Connection::send( const Message& msg, unsigned int* serial ) +{ + return dbus_connection_send(_pvt->conn, msg._pvt->msg, serial); +} + +Message Connection::send_blocking( Message& msg, int timeout ) +{ + DBusMessage* reply; + InternalError e; + + reply = dbus_connection_send_with_reply_and_block(_pvt->conn, msg._pvt->msg, timeout, e); + + if(e) throw Error(e); + + return Message(new Message::Private(reply), false); +} + +PendingCall Connection::send_async( Message& msg, int timeout ) +{ + DBusPendingCall* pending; + + if(!dbus_connection_send_with_reply(_pvt->conn, msg._pvt->msg, &pending, timeout)) + { + throw ErrorNoMemory("Unable to start asynchronous call"); + } + return PendingCall(new PendingCall::Private(pending)); +} + +void Connection::request_name( const char* name, int flags ) +{ + InternalError e; + + debug_log("%s: registering bus name %s", unique_name(), name); + + dbus_bus_request_name(_pvt->conn, name, flags, e); //we deliberately don't check return value + + if(e) throw Error(e); + +// this->remove_match("destination"); + + if(name) + { + _pvt->names.push_back(name); + std::string match = "destination='" + _pvt->names.back() + "'"; + add_match(match.c_str()); + } +} + +bool Connection::has_name( const char* name ) +{ + InternalError e; + + bool b = dbus_bus_name_has_owner(_pvt->conn, name, e); + + if(e) throw Error(e); + + return b; +} + +const std::vector& Connection::names() +{ + return _pvt->names; +} + +bool Connection::start_service( const char* name, unsigned long flags ) +{ + InternalError e; + + bool b = dbus_bus_start_service_by_name(_pvt->conn, name, flags, NULL, e); + + if(e) throw Error(e); + + return b; +} + Index: /tags/2.0-rc2/external/dbus/src/introspection.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/introspection.cpp (revision 575) +++ /tags/2.0-rc2/external/dbus/src/introspection.cpp (revision 575) @@ -0,0 +1,185 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include +#include + +#include + +#include + +using namespace DBus; + +static const char* introspectable_name = "org.freedesktop.DBus.Introspectable"; + +IntrospectableAdaptor::IntrospectableAdaptor() +: InterfaceAdaptor(introspectable_name) +{ + register_method(IntrospectableAdaptor, Introspect, Introspect); +} + +Message IntrospectableAdaptor::Introspect( const CallMessage& call ) +{ + debug_log("requested introspection data"); + + std::ostringstream xml; + + xml << DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE; + + const std::string path = object()->path(); + + xml << ""; + + InterfaceAdaptorTable::const_iterator iti; + + for(iti = _interfaces.begin(); iti != _interfaces.end(); ++iti) + { + debug_log("introspecting interface %s", iti->first.c_str()); + + IntrospectedInterface* const intro = iti->second->introspect(); + if(intro) + { + xml << "name << "\">"; + + for(const IntrospectedProperty* p = intro->properties; p->name; ++p) + { + std::string access; + + if(p->read) access += "read"; + if(p->write) access += "write"; + + xml << "name << "\"" + << " type=\"" << p->type << "\"" + << " access=\"" << access << "\"/>"; + } + + for(const IntrospectedMethod* m = intro->methods; m->args; ++m) + { + xml << "name << "\">"; + + for(const IntrospectedArgument* a = m->args; a->type; ++a) + { + xml << "in ? "in" : "out") << "\"" + << " type=\"" << a->type << "\""; + + if(a->name) xml << " name=\"" << a->name << "\""; + + xml << "/>"; + } + + xml << ""; + } + + for(const IntrospectedMethod* m = intro->signals; m->args; ++m) + { + xml << "name << "\">"; + + for(const IntrospectedArgument* a = m->args; a->type; ++a) + { + xml << "type << "\""; + + if(a->name) xml << " name=\"" << a->name << "\""; + + xml << "/>"; + } + xml << ""; + } + + xml << ""; + } + } + const ObjectAdaptorPList children = ObjectAdaptor::from_path_prefix(path + '/'); + + ObjectAdaptorPList::const_iterator oci; + + debug_log("nb children: %d", children.size()); + for(oci = children.begin(); oci != children.end(); ++oci) + { + + std::string name = (*oci)->path().substr(path.length()+1); + + std::string::size_type loc = name.find('/'); + if( loc != std::string::npos ) { + name.substr(loc); + } + + xml << ""; + } + + xml << ""; + + ReturnMessage reply(call); + MessageIter wi = reply.writer(); + wi.append_string(xml.str().c_str()); + return reply; +} + +IntrospectedInterface* const IntrospectableAdaptor::introspect() const +{ + static IntrospectedArgument Introspect_args[] = + { + { "data", "s", false }, + { 0, 0, 0 } + }; + static IntrospectedMethod Introspectable_methods[] = + { + { "Introspect", Introspect_args }, + { 0, 0 } + }; + static IntrospectedMethod Introspectable_signals[] = + { + { 0, 0 } + }; + static IntrospectedProperty Introspectable_properties[] = + { + { 0, 0, 0, 0 } + }; + static IntrospectedInterface Introspectable_interface = + { + introspectable_name, + Introspectable_methods, + Introspectable_signals, + Introspectable_properties + }; + return &Introspectable_interface; +} + +IntrospectableProxy::IntrospectableProxy() +: InterfaceProxy(introspectable_name) +{} + +std::string IntrospectableProxy::Introspect() +{ + DBus::CallMessage call; + + call.member("Introspect"); + + DBus::Message ret = invoke_method(call); + + DBus::MessageIter ri = ret.reader(); + const char* str = ri.get_string(); + + return str; +} Index: /tags/2.0-rc2/external/dbus/src/interface.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/interface.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/interface.cpp (revision 562) @@ -0,0 +1,148 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include + +#include "internalerror.h" + +using namespace DBus; + +Interface::Interface( const std::string& name ) +: _name(name) +{} + +Interface::~Interface() +{} + +InterfaceAdaptor* AdaptorBase::find_interface( const std::string& name ) +{ + InterfaceAdaptorTable::const_iterator ii = _interfaces.find(name); + + return ii != _interfaces.end() ? ii->second : NULL; +} + +InterfaceAdaptor::InterfaceAdaptor( const std::string& name ) +: Interface(name) +{ + debug_log("adding interface %s", name.c_str()); + + _interfaces[name] = this; +} + +Message InterfaceAdaptor::dispatch_method( const CallMessage& msg ) +{ + const char* name = msg.member(); + + MethodTable::iterator mi = _methods.find(name); + if( mi != _methods.end() ) + { + return mi->second.call( msg ); + } + else + { + return ErrorMessage(msg, DBUS_ERROR_UNKNOWN_METHOD, name); + } +} + +void InterfaceAdaptor::emit_signal( const SignalMessage& sig ) +{ + SignalMessage& sig2 = const_cast(sig); + + sig2.interface( name().c_str() ); + _emit_signal(sig2); +} + +Variant* InterfaceAdaptor::get_property( const std::string& name ) +{ + PropertyTable::iterator pti = _properties.find(name); + + if( pti != _properties.end() ) + { + if( !pti->second.read ) + throw ErrorAccessDenied("property is not readable"); + + return &(pti->second.value); + } + return NULL; +} + +void InterfaceAdaptor::set_property( const std::string& name, Variant& value ) +{ + PropertyTable::iterator pti = _properties.find(name); + + if( pti != _properties.end() ) + { + if( !pti->second.write ) + throw ErrorAccessDenied("property is not writeable"); + + Signature sig = value.signature(); + + if( pti->second.sig != sig ) + throw ErrorInvalidSignature("property expects a different type"); + + pti->second.value = value; + return; + } + throw ErrorFailed("requested property not found"); +} + +InterfaceProxy* ProxyBase::find_interface( const std::string& name ) +{ + InterfaceProxyTable::const_iterator ii = _interfaces.find(name); + + return ii != _interfaces.end() ? ii->second : NULL; +} + +InterfaceProxy::InterfaceProxy( const std::string& name ) +: Interface(name) +{ + debug_log("adding interface %s", name.c_str()); + + _interfaces[name] = this; +} + +bool InterfaceProxy::dispatch_signal( const SignalMessage& msg ) +{ + const char* name = msg.member(); + + SignalTable::iterator si = _signals.find(name); + if( si != _signals.end() ) + { + si->second.call( msg ); + return true; + } + else + { + return false; + } +} + +Message InterfaceProxy::invoke_method( const CallMessage& call ) +{ + CallMessage& call2 = const_cast(call); + + call2.interface( name().c_str() ); + return _invoke_method(call2); +} Index: /tags/2.0-rc2/external/dbus/src/pendingcall_p.h =================================================================== --- /tags/2.0-rc2/external/dbus/src/pendingcall_p.h (revision 562) +++ /tags/2.0-rc2/external/dbus/src/pendingcall_p.h (revision 562) @@ -0,0 +1,53 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_PENDING_CALL_P_H +#define __DBUSXX_PENDING_CALL_P_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +namespace DBus { + +struct DXXAPILOCAL PendingCall::Private +{ + DBusPendingCall* call; + int dataslot; + + Private( DBusPendingCall* ); + + ~Private(); + + static void notify_stub( DBusPendingCall* dpc, void* data ); +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_PENDING_CALL_P_H Index: /tags/2.0-rc2/external/dbus/src/types.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/types.cpp (revision 1235) +++ /tags/2.0-rc2/external/dbus/src/types.cpp (revision 1235) @@ -0,0 +1,104 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include +#include +#include + +#include "message_p.h" +#include "internalerror.h" + +#include + +using namespace DBus; + +Variant::Variant() +: _msg(CallMessage()) // dummy message used as temporary storage for variant data +{ +} + +Variant::Variant( MessageIter& it ) +: _msg(CallMessage()) +{ + MessageIter vi = it.recurse(); + MessageIter mi = _msg.writer(); + vi.copy_data(mi); +} + +Variant& Variant::operator = ( const Variant& v ) +{ + if(&v != this) + { + _msg = v._msg; + } + return *this; +} + +void Variant::clear() +{ + CallMessage empty; + _msg = empty; +} + +const Signature Variant::signature() const +{ + char* sigbuf = reader().signature(); + + Signature signature = sigbuf; + + free(sigbuf); + + return signature; +} + +MessageIter& operator << ( MessageIter& iter, const Variant& val ) +{ + const Signature sig = val.signature(); + + MessageIter rit = val.reader(); + MessageIter wit = iter.new_variant(sig.c_str()); + + rit.copy_data(wit); + + iter.close_container(wit); + + return iter; +} + +MessageIter& operator >> ( MessageIter& iter, Variant& val ) +{ + if(iter.type() != DBUS_TYPE_VARIANT) + throw ErrorInvalidArgs("variant type expected"); + + val.clear(); + + MessageIter vit = iter.recurse(); + MessageIter mit = val.writer(); + + vit.copy_data(mit); + + return ++iter; +} + Index: /tags/2.0-rc2/external/dbus/src/object.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/object.cpp (revision 1235) +++ /tags/2.0-rc2/external/dbus/src/object.cpp (revision 1235) @@ -0,0 +1,354 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include +#include "internalerror.h" + +#include +#include + +#include "message_p.h" +#include "server_p.h" +#include "connection_p.h" + +#include + +using namespace DBus; + +Object::Object( Connection& conn, const Path& path, const char* service ) +: _conn(conn), _path(path), _service(service ? service : "") +{ +} + +Object::~Object() +{ +} + +struct ObjectAdaptor::Private +{ + static void unregister_function_stub( DBusConnection*, void* ); + static DBusHandlerResult message_function_stub( DBusConnection*, DBusMessage*, void* ); +}; + +static DBusObjectPathVTable _vtable = +{ + ObjectAdaptor::Private::unregister_function_stub, + ObjectAdaptor::Private::message_function_stub, + NULL, NULL, NULL, NULL +}; + +void ObjectAdaptor::Private::unregister_function_stub( DBusConnection* conn, void* data ) +{ + //TODO: what do we have to do here ? +} + +DBusHandlerResult ObjectAdaptor::Private::message_function_stub( DBusConnection*, DBusMessage* dmsg, void* data ) +{ + ObjectAdaptor* o = static_cast(data); + + if( o ) + { + Message msg(new Message::Private(dmsg)); + + debug_log("in object %s", o->path().c_str()); + debug_log(" got message #%d from %s to %s", + msg.serial(), + msg.sender(), + msg.destination() + ); + + return o->handle_message(msg) + ? DBUS_HANDLER_RESULT_HANDLED + : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + else + { + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } +} + +typedef std::map ObjectAdaptorTable; +static ObjectAdaptorTable _adaptor_table; + +ObjectAdaptor* ObjectAdaptor::from_path( const Path& path ) +{ + ObjectAdaptorTable::iterator ati = _adaptor_table.find(path); + + if(ati != _adaptor_table.end()) + return ati->second; + + return NULL; +} + +ObjectAdaptorPList ObjectAdaptor::from_path_prefix( const std::string& prefix ) +{ + ObjectAdaptorPList ali; + + ObjectAdaptorTable::iterator ati = _adaptor_table.begin(); + + size_t plen = prefix.length(); + + while(ati != _adaptor_table.end()) + { + if(!strncmp(ati->second->path().c_str(), prefix.c_str(), plen)) + ali.push_back(ati->second); + + ++ati; + } + + return ali; +} + +ObjectAdaptor::ObjectAdaptor( Connection& conn, const Path& path ) +: Object(conn, path, conn.unique_name()) +{ + register_obj(); +} + +ObjectAdaptor::~ObjectAdaptor() +{ + unregister_obj(); +} + +void ObjectAdaptor::register_obj() +{ + debug_log("registering local object %s", path().c_str()); + + if(!dbus_connection_register_object_path(conn()._pvt->conn, path().c_str(), &_vtable, this)) + { + throw ErrorNoMemory("unable to register object path"); + } + else + { + InterfaceAdaptorTable::const_iterator ii = _interfaces.begin(); + while( ii != _interfaces.end() ) + { + std::string im = "type='method_call',interface='"+ii->first+"',path='"+path()+"'"; + conn().add_match(im.c_str()); + ++ii; + } + } + + _adaptor_table[path()] = this; +} + +void ObjectAdaptor::unregister_obj() +{ + _adaptor_table.erase(path()); + + debug_log("unregistering local object %s", path().c_str()); + + dbus_connection_unregister_object_path(conn()._pvt->conn, path().c_str()); + + InterfaceAdaptorTable::const_iterator ii = _interfaces.begin(); + while( ii != _interfaces.end() ) + { + std::string im = "type='method_call',interface='"+ii->first+"',path='"+path()+"'"; + conn().remove_match(im.c_str()); + ++ii; + } +} + +void ObjectAdaptor::_emit_signal( SignalMessage& sig ) +{ + sig.path(path().c_str()); + + conn().send(sig); +} + +struct ReturnLaterError +{ + const Tag* tag; +}; + +bool ObjectAdaptor::handle_message( const Message& msg ) +{ + switch( msg.type() ) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + { + const CallMessage& cmsg = reinterpret_cast(msg); + const char* member = cmsg.member(); + const char* interface = cmsg.interface(); + + debug_log(" invoking method %s.%s", interface, member); + + InterfaceAdaptor* ii = find_interface(interface); + if( ii ) + { + try + { + Message ret = ii->dispatch_method(cmsg); + conn().send(ret); + } + catch(Error& e) + { + ErrorMessage em(cmsg, e.name(), e.message()); + conn().send(em); + } + catch(ReturnLaterError& rle) + { + _continuations[rle.tag] = new Continuation(conn(), cmsg, rle.tag); + } + return true; + } + else + { + return false; + } + } + default: + { + return false; + } + } +} + +void ObjectAdaptor::return_later( const Tag* tag ) +{ + ReturnLaterError rle = { tag }; + throw rle; +} + +void ObjectAdaptor::return_now( Continuation* ret ) +{ + ret->_conn.send(ret->_return); + + ContinuationMap::iterator di = _continuations.find(ret->_tag); + + delete di->second; + + _continuations.erase(di); +} + +void ObjectAdaptor::return_error( Continuation* ret, const Error error ) +{ + ret->_conn.send(ErrorMessage(ret->_call, error.name(), error.message())); + + ContinuationMap::iterator di = _continuations.find(ret->_tag); + + delete di->second; + + _continuations.erase(di); +} + +ObjectAdaptor::Continuation* ObjectAdaptor::find_continuation( const Tag* tag ) +{ + ContinuationMap::iterator di = _continuations.find(tag); + + return di != _continuations.end() ? di->second : NULL; +} + +ObjectAdaptor::Continuation::Continuation( Connection& conn, const CallMessage& call, const Tag* tag ) +: _conn(conn), _call(call), _return(_call), _tag(tag) +{ + _writer = _return.writer(); //todo: verify +} + +/* +*/ + +ObjectProxy::ObjectProxy( Connection& conn, const Path& path, const char* service ) +: Object(conn, path, service) +{ + register_obj(); +} + +ObjectProxy::~ObjectProxy() +{ + unregister_obj(); +} + +void ObjectProxy::register_obj() +{ + debug_log("registering remote object %s", path().c_str()); + + _filtered = new Callback(this, &ObjectProxy::handle_message); + + conn().add_filter(_filtered); + + InterfaceProxyTable::const_iterator ii = _interfaces.begin(); + while( ii != _interfaces.end() ) + { + std::string im = "type='signal',interface='"+ii->first+"',path='"+path()+"'"; + conn().add_match(im.c_str()); + ++ii; + } +} + +void ObjectProxy::unregister_obj() +{ + debug_log("unregistering remote object %s", path().c_str()); + + InterfaceProxyTable::const_iterator ii = _interfaces.begin(); + while( ii != _interfaces.end() ) + { + std::string im = "type='signal',interface='"+ii->first+"',path='"+path()+"'"; + conn().remove_match(im.c_str()); + ++ii; + } + conn().remove_filter(_filtered); +} + +Message ObjectProxy::_invoke_method( CallMessage& call ) +{ + call.path(path().c_str()); + call.destination(service().c_str()); + + return conn().send_blocking(call, 2000); +} + +bool ObjectProxy::handle_message( const Message& msg ) +{ + switch( msg.type() ) + { + case DBUS_MESSAGE_TYPE_SIGNAL: + { + const SignalMessage& smsg = reinterpret_cast(msg); + const char* interface = smsg.interface(); + const char* member = smsg.member(); + const char* objpath = smsg.path(); + + if( objpath != path() ) return false; + + debug_log("filtered signal %s(in %s) from %s to object %s", + member, interface, msg.sender(), objpath); + + InterfaceProxy* ii = find_interface(interface); + if( ii ) + { + return ii->dispatch_signal(smsg); + } + else + { + return false; + } + } + default: + { + return false; + } + } +} Index: /tags/2.0-rc2/external/dbus/src/server.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/server.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/server.cpp (revision 562) @@ -0,0 +1,126 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include + +#include "internalerror.h" +#include "server_p.h" +#include "connection_p.h" +#include "dispatcher_p.h" + +using namespace DBus; + +Server::Private::Private( DBusServer* s ) +: server(s) +{ +} + +Server::Private::~Private() +{ +} + +void Server::Private::on_new_conn_cb( DBusServer* server, DBusConnection* conn, void* data ) +{ + Server* s = static_cast(data); + + Connection nc (new Connection::Private(conn, s->_pvt.get())); + + s->_pvt->connections.push_back(nc); + + s->on_new_connection(nc); + + debug_log("incoming connection 0x%08x", conn); +} + +Server::Server( const char* address ) +{ + InternalError e; + DBusServer* server = dbus_server_listen(address, e); + + if(e) throw Error(e); + + debug_log("server 0x%08x listening on %s", server, address); + + _pvt = new Private(server); + + dbus_server_set_new_connection_function(_pvt->server, Private::on_new_conn_cb, this, NULL); + + setup(default_dispatcher); +} +/* +Server::Server( const Server& s ) +: _pvt(s._pvt) +{ + dbus_server_ref(_pvt->server); +} +*/ +Server::~Server() +{ + dbus_server_unref(_pvt->server); +} + +Dispatcher* Server::setup( Dispatcher* dispatcher ) +{ + debug_log("registering stubs for server %p", _pvt->server); + + Dispatcher* prev = _pvt->dispatcher; + + dbus_server_set_watch_functions( + _pvt->server, + Dispatcher::Private::on_add_watch, + Dispatcher::Private::on_rem_watch, + Dispatcher::Private::on_toggle_watch, + dispatcher, + 0 + ); + + dbus_server_set_timeout_functions( + _pvt->server, + Dispatcher::Private::on_add_timeout, + Dispatcher::Private::on_rem_timeout, + Dispatcher::Private::on_toggle_timeout, + dispatcher, + 0 + ); + + _pvt->dispatcher = dispatcher; + + return prev; +} + +bool Server::operator == ( const Server& s ) const +{ + return _pvt->server == s._pvt->server; +} + +bool Server::listening() const +{ + return dbus_server_get_is_connected(_pvt->server); +} +void Server::disconnect() +{ + dbus_server_disconnect(_pvt->server); +} + Index: /tags/2.0-rc2/external/dbus/src/message_p.h =================================================================== --- /tags/2.0-rc2/external/dbus/src/message_p.h (revision 562) +++ /tags/2.0-rc2/external/dbus/src/message_p.h (revision 562) @@ -0,0 +1,52 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_MESSAGE_P_H +#define __DBUSXX_MESSAGE_P_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +namespace DBus { + +struct DXXAPILOCAL Message::Private +{ + DBusMessage* msg; + + Private() : msg(0) + {} + + Private( DBusMessage* m ) : msg(m) + {} +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_MESSAGE_P_H Index: /tags/2.0-rc2/external/dbus/src/dispatcher_p.h =================================================================== --- /tags/2.0-rc2/external/dbus/src/dispatcher_p.h (revision 562) +++ /tags/2.0-rc2/external/dbus/src/dispatcher_p.h (revision 562) @@ -0,0 +1,57 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_DISPATCHER_P_H +#define __DBUSXX_DISPATCHER_P_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +#include "internalerror.h" + +namespace DBus { + +struct DXXAPILOCAL Dispatcher::Private +{ + static dbus_bool_t on_add_watch( DBusWatch* watch, void* data ); + + static void on_rem_watch( DBusWatch* watch, void* data ); + + static void on_toggle_watch( DBusWatch* watch, void* data ); + + static dbus_bool_t on_add_timeout( DBusTimeout* timeout, void* data ); + + static void on_rem_timeout( DBusTimeout* timeout, void* data ); + + static void on_toggle_timeout( DBusTimeout* timeout, void* data ); +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_DISPATCHER_P_H Index: /tags/2.0-rc2/external/dbus/src/eventloop.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/eventloop.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/eventloop.cpp (revision 562) @@ -0,0 +1,311 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include + +#include +#include + +#include + +using namespace DBus; + +static double millis( timeval tv ) +{ + return (tv.tv_sec*1000.0 + tv.tv_usec/1000.0); +} + +EepleTimeout::EepleTimeout( int interval, bool repeat, EepleMainLoop* ed ) +: _enabled(true), _interval(interval), _repeat(repeat), _expiration(0), _data(0), _disp(ed) +{ + timeval now; + gettimeofday(&now, NULL); + + _expiration = millis(now) + interval; + + _disp->_timeouts.push_back(this); +} + +EepleTimeout::~EepleTimeout() +{ + _disp->_timeouts.remove(this); +} + +EepleWatch::EepleWatch( int fd, int flags, EepleMainLoop* ed ) +: _enabled(true), _fd(fd), _flags(flags), _state(0), _data(0), _disp(ed) +{ + _disp->_watches.push_back(this); +} + +EepleWatch::~EepleWatch() +{ + _disp->_watches.remove(this); +} + +EepleMainLoop::EepleMainLoop() +{ +} + +EepleMainLoop::~EepleMainLoop() +{ + Watches::iterator wi = _watches.begin(); + while(wi != _watches.end()) + { + Watches::iterator wmp = wi; + ++wmp; + delete (*wi); + wi = wmp; + } + + Timeouts::iterator ti = _timeouts.begin(); + while(ti != _timeouts.end()) + { + Timeouts::iterator tmp = ti; + ++tmp; + delete (*ti); + ti = tmp; + } +} + +void EepleMainLoop::dispatch() +{ + int nfd = _watches.size(); + + pollfd fds[nfd]; + + Watches::iterator wi = _watches.begin(); + + for(nfd = 0; wi != _watches.end(); ++wi) + { + if((*wi)->enabled()) + { + fds[nfd].fd = (*wi)->descriptor(); + fds[nfd].events = (*wi)->flags(); + fds[nfd].revents = 0; + + ++nfd; + } + } + + int wait_min = 10000; + + Timeouts::iterator ti; + + for(ti = _timeouts.begin(); ti != _timeouts.end(); ++ti) + { + if((*ti)->enabled() && (*ti)->interval() < wait_min) + wait_min = (*ti)->interval(); + } + + //int rfd = poll(fds, nfd, wait_min); + //if(rfd) debug_log("%d descriptors ready"); + + poll(fds, nfd, wait_min); + + timeval now; + gettimeofday(&now, NULL); + + double now_millis = millis(now); + + ti = _timeouts.begin(); + + while(ti != _timeouts.end()) + { + Timeouts::iterator tmp = ti; + ++tmp; + + if((*ti)->enabled() && now_millis >= (*ti)->_expiration) + { + (*ti)->expired(*(*ti)); + + if((*ti)->_repeat) + { + (*ti)->_expiration = now_millis + (*ti)->_interval; + } + + } + + ti = tmp; + } + + for(int j = 0; j < nfd; ++j) + { + Watches::iterator wi; + + for(wi = _watches.begin(); wi != _watches.end();) + { + Watches::iterator tmp = wi; + ++tmp; + + if((*wi)->enabled() && (*wi)->_fd == fds[j].fd) + { + if(fds[j].revents) + { + (*wi)->_state = fds[j].revents; + + (*wi)->ready(*(*wi)); + + fds[j].revents = 0; + } + } + + wi = tmp; + } + } +} + +/* +*/ + +BusTimeout::BusTimeout( Timeout::Internal* ti, BusDispatcher* bd ) +: Timeout(ti), EepleTimeout(Timeout::interval(), true, bd) +{ + EepleTimeout::enabled(Timeout::enabled()); +} + +void BusTimeout::toggle() +{ + debug_log("timeout %p toggled (%s)", this, Timeout::enabled() ? "on":"off"); + + EepleTimeout::enabled(Timeout::enabled()); +} + +BusWatch::BusWatch( Watch::Internal* wi, BusDispatcher* bd ) +: Watch(wi), EepleWatch(Watch::descriptor(), 0, bd) +{ + int flags = POLLHUP | POLLERR; + + if(Watch::flags() & DBUS_WATCH_READABLE) + flags |= POLLIN; + if(Watch::flags() & DBUS_WATCH_WRITABLE) + flags |= POLLOUT; + + EepleWatch::flags(flags); + EepleWatch::enabled(Watch::enabled()); +} + +void BusWatch::toggle() +{ + debug_log("watch %p toggled (%s)", this, Watch::enabled() ? "on":"off"); + + EepleWatch::enabled(Watch::enabled()); +} + +void BusDispatcher::enter() +{ + debug_log("entering dispatcher %p", this); + + _running = true; + + while(_running) + { + do_iteration(); + } + + debug_log("leaving dispatcher %p", this); +} + +void BusDispatcher::leave() +{ + _running = false; +} + +void BusDispatcher::do_iteration() +{ + dispatch_pending(); + dispatch(); +} + +Timeout* BusDispatcher::add_timeout( Timeout::Internal* ti ) +{ + BusTimeout* bt = new BusTimeout(ti, this); + + bt->expired = new Callback(this, &BusDispatcher::timeout_expired); + bt->data(bt); + + debug_log("added timeout %p (%s)", bt, ((Timeout*)bt)->enabled() ? "on":"off"); + + return bt; +} + +void BusDispatcher::rem_timeout( Timeout* t ) +{ + debug_log("removed timeout %p", t); + + delete t; +} + +Watch* BusDispatcher::add_watch( Watch::Internal* wi ) +{ + BusWatch* bw = new BusWatch(wi, this); + + bw->ready = new Callback(this, &BusDispatcher::watch_ready); + bw->data(bw); + + debug_log("added watch %p (%s) fd=%d flags=%d", + bw, ((Watch*)bw)->enabled() ? "on":"off", ((Watch*)bw)->descriptor(), ((Watch*)bw)->flags() + ); + + return bw; +} + +void BusDispatcher::rem_watch( Watch* w ) +{ + debug_log("removed watch %p", w); + + delete w; +} + +void BusDispatcher::timeout_expired( EepleTimeout& et ) +{ + debug_log("timeout %p expired", &et); + + BusTimeout* timeout = reinterpret_cast(et.data()); + + timeout->handle(); +} + +void BusDispatcher::watch_ready( EepleWatch& ew ) +{ + BusWatch* watch = reinterpret_cast(ew.data()); + + debug_log("watch %p ready, flags=%d state=%d", + watch, ((Watch*)watch)->flags(), watch->state() + ); + + int flags = 0; + + if(watch->state() & POLLIN) + flags |= DBUS_WATCH_READABLE; + if(watch->state() & POLLOUT) + flags |= DBUS_WATCH_WRITABLE; + if(watch->state() & POLLHUP) + flags |= DBUS_WATCH_HANGUP; + if(watch->state() & POLLERR) + flags |= DBUS_WATCH_ERROR; + + watch->handle(flags); +} + Index: /tags/2.0-rc2/external/dbus/src/pendingcall.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/pendingcall.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/pendingcall.cpp (revision 562) @@ -0,0 +1,105 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include + +#include + +#include "internalerror.h" +#include "pendingcall_p.h" + +using namespace DBus; + +PendingCall::Private::Private( DBusPendingCall* dpc ) +: call(dpc), dataslot(-1) +{ + if(!dbus_pending_call_allocate_data_slot(&dataslot)) + { + throw ErrorNoMemory("Unable to allocate data slot"); + } +} + +void PendingCall::Private::notify_stub( DBusPendingCall* dpc, void* data ) +{ + PendingCall* pc = static_cast(data); + + pc->slot(*pc); +} + +PendingCall::Private::~Private() +{ + if(dataslot != -1) + { + dbus_pending_call_allocate_data_slot(&dataslot); + } +} + +PendingCall::PendingCall( PendingCall::Private* p ) +: _pvt(p) +{ + if(!dbus_pending_call_set_notify(_pvt->call, Private::notify_stub, this, NULL)) + { + throw ErrorNoMemory("Unable to initialize pending call"); + } +} + +PendingCall::PendingCall( const PendingCall& c ) +: _pvt(c._pvt) +{ + dbus_pending_call_ref(_pvt->call); +} + +PendingCall::~PendingCall() +{ + dbus_pending_call_unref(_pvt->call); +} + +bool PendingCall::completed() +{ + return dbus_pending_call_get_completed(_pvt->call); +} + +void PendingCall::cancel() +{ + dbus_pending_call_cancel(_pvt->call); +} + +void PendingCall::block() +{ + dbus_pending_call_block(_pvt->call); +} + +void PendingCall::data( void* p ) +{ + if(!dbus_pending_call_set_data(_pvt->call, _pvt->dataslot, p, NULL)) + { + throw ErrorNoMemory("Unable to initialize data slot"); + } +} + +void* PendingCall::data() +{ + return dbus_pending_call_get_data(_pvt->call, _pvt->dataslot); +} + Index: /tags/2.0-rc2/external/dbus/src/connection_p.h =================================================================== --- /tags/2.0-rc2/external/dbus/src/connection_p.h (revision 562) +++ /tags/2.0-rc2/external/dbus/src/connection_p.h (revision 562) @@ -0,0 +1,73 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_CONNECTION_P_H +#define __DBUSXX_CONNECTION_P_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#include + +namespace DBus { + +struct DXXAPILOCAL Connection::Private +{ + DBusConnection* conn; + + std::vector names; + + Dispatcher* dispatcher; + bool do_dispatch(); + + MessageSlot disconn_filter; + bool disconn_filter_function( const Message& ); + + Server::Private* server; + void detach_server(); + + Private( DBusConnection*, Server::Private* = NULL ); + + Private( DBusBusType ); + + ~Private(); + + void init(); + + static void dispatch_status_stub( DBusConnection*, DBusDispatchStatus, void* ); + + static DBusHandlerResult message_filter_stub( DBusConnection*, DBusMessage*, void* ); +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_CONNECTION_P_H Index: /tags/2.0-rc2/external/dbus/src/message.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/message.cpp (revision 1235) +++ /tags/2.0-rc2/external/dbus/src/message.cpp (revision 1235) @@ -0,0 +1,640 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include + +#include + +#include "internalerror.h" +#include "message_p.h" + +#include + +using namespace DBus; + +/* +*/ + +int MessageIter::type() +{ + return dbus_message_iter_get_arg_type((DBusMessageIter*)&_iter); +} + +bool MessageIter::at_end() +{ + return type() == DBUS_TYPE_INVALID; +} + +bool MessageIter::has_next() +{ + return dbus_message_iter_has_next((DBusMessageIter*)&_iter); +} + +MessageIter& MessageIter::operator ++() +{ + dbus_message_iter_next((DBusMessageIter*)&_iter); + return (*this); +} + +MessageIter MessageIter::operator ++(int) +{ + MessageIter copy(*this); + ++(*this); + return copy; +} + +bool MessageIter::append_basic( int type_id, void* value ) +{ + return dbus_message_iter_append_basic((DBusMessageIter*)&_iter, type_id, value); +} + +void MessageIter::get_basic( int type_id, void* ptr ) +{ + if(type() != type_id) + throw ErrorInvalidArgs("type mismatch"); + + dbus_message_iter_get_basic((DBusMessageIter*)_iter, ptr); +} + +bool MessageIter::append_byte( unsigned char b ) +{ + return append_basic(DBUS_TYPE_BYTE, &b); +} + +unsigned char MessageIter::get_byte() +{ + unsigned char b; + get_basic(DBUS_TYPE_BYTE, &b); + return b; +} + +bool MessageIter::append_bool( bool b ) +{ + dbus_bool_t db = b; + return append_basic(DBUS_TYPE_BOOLEAN, &db); +} + +bool MessageIter::get_bool() +{ + dbus_bool_t db; + get_basic(DBUS_TYPE_BOOLEAN, &db); + return (bool)db; +} + +bool MessageIter::append_int16( signed short i ) +{ + return append_basic(DBUS_TYPE_INT16, &i); +} + +signed short MessageIter::get_int16() +{ + signed short i; + get_basic(DBUS_TYPE_INT16, &i); + return i; +} + +bool MessageIter::append_uint16( unsigned short u ) +{ + return append_basic(DBUS_TYPE_UINT16, &u); +} + +unsigned short MessageIter::get_uint16() +{ + unsigned short u; + get_basic(DBUS_TYPE_UINT16, &u); + return u; +} + +bool MessageIter::append_int32( signed int i ) +{ + return append_basic(DBUS_TYPE_INT32, &i); +} + +signed int MessageIter::get_int32() +{ + signed int i; + get_basic(DBUS_TYPE_INT32, &i); + return i; +} + +bool MessageIter::append_uint32( unsigned int u ) +{ + return append_basic(DBUS_TYPE_UINT32, &u); +} + +unsigned int MessageIter::get_uint32() +{ + unsigned int u; + get_basic(DBUS_TYPE_UINT32, &u); + return u; +} + +signed long long MessageIter::get_int64() +{ + signed long long i; + get_basic(DBUS_TYPE_INT64, &i); + return i; +} + +bool MessageIter::append_int64( signed long long i ) +{ + return append_basic(DBUS_TYPE_INT64, &i); +} + +unsigned long long MessageIter::get_uint64() +{ + unsigned long long u; + get_basic(DBUS_TYPE_UINT64, &u); + return u; +} + +bool MessageIter::append_uint64( unsigned long long u ) +{ + return append_basic(DBUS_TYPE_UINT64, &u); +} + +double MessageIter::get_double() +{ + double d; + get_basic(DBUS_TYPE_DOUBLE, &d); + return d; +} + +bool MessageIter::append_double( double d ) +{ + return append_basic(DBUS_TYPE_DOUBLE, &d); +} + +bool MessageIter::append_string( const char* chars ) +{ + return append_basic(DBUS_TYPE_STRING, &chars); +} + +const char* MessageIter::get_string() +{ + char* chars; + get_basic(DBUS_TYPE_STRING, &chars); + return chars; +} + +bool MessageIter::append_path( const char* chars ) +{ + return append_basic(DBUS_TYPE_OBJECT_PATH, &chars); +} + +const char* MessageIter::get_path() +{ + char* chars; + get_basic(DBUS_TYPE_OBJECT_PATH, &chars); + return chars; +} + +bool MessageIter::append_signature( const char* chars ) +{ + return append_basic(DBUS_TYPE_SIGNATURE, &chars); +} + +const char* MessageIter::get_signature() +{ + char* chars; + get_basic(DBUS_TYPE_SIGNATURE, &chars); + return chars; +} + +MessageIter MessageIter::recurse() +{ + MessageIter iter(msg()); + dbus_message_iter_recurse((DBusMessageIter*)&_iter, (DBusMessageIter*)&(iter._iter)); + return iter; +} + +char* MessageIter::signature() const +{ + return dbus_message_iter_get_signature((DBusMessageIter*)&_iter); +} + +bool MessageIter::append_array( char type, const void* ptr, size_t length ) +{ + return dbus_message_iter_append_fixed_array((DBusMessageIter*)&_iter, type, &ptr, length); +} + +int MessageIter::array_type() +{ + return dbus_message_iter_get_element_type((DBusMessageIter*)&_iter); +} + +int MessageIter::get_array( void* ptr ) +{ + int length; + dbus_message_iter_get_fixed_array((DBusMessageIter*)&_iter, ptr, &length); + return length; +} + +bool MessageIter::is_array() +{ + return dbus_message_iter_get_arg_type((DBusMessageIter*)&_iter) == DBUS_TYPE_ARRAY; +} + +bool MessageIter::is_dict() +{ + return is_array() && dbus_message_iter_get_element_type((DBusMessageIter*)_iter) == DBUS_TYPE_DICT_ENTRY; +} + +MessageIter MessageIter::new_array( const char* sig ) +{ + MessageIter arr(msg()); + dbus_message_iter_open_container( + (DBusMessageIter*)&_iter, DBUS_TYPE_ARRAY, sig, (DBusMessageIter*)&(arr._iter) + ); + return arr; +} + +MessageIter MessageIter::new_variant( const char* sig ) +{ + MessageIter var(msg()); + dbus_message_iter_open_container( + (DBusMessageIter*)_iter, DBUS_TYPE_VARIANT, sig, (DBusMessageIter*)&(var._iter) + ); + return var; +} + +MessageIter MessageIter::new_struct() +{ + MessageIter stu(msg()); + dbus_message_iter_open_container( + (DBusMessageIter*)_iter, DBUS_TYPE_STRUCT, NULL, (DBusMessageIter*)&(stu._iter) + ); + return stu; +} + +MessageIter MessageIter::new_dict_entry() +{ + MessageIter ent(msg()); + dbus_message_iter_open_container( + (DBusMessageIter*)_iter, DBUS_TYPE_DICT_ENTRY, NULL, (DBusMessageIter*)&(ent._iter) + ); + return ent; +} + +void MessageIter::close_container( MessageIter& container ) +{ + dbus_message_iter_close_container((DBusMessageIter*)&_iter, (DBusMessageIter*)&(container._iter)); +} + +static bool is_basic_type(int typecode) +{ + switch(typecode) + { + case 'y': + case 'b': + case 'n': + case 'q': + case 'i': + case 'u': + case 'x': + case 't': + case 'd': + case 's': + case 'o': + case 'g': + return true; + default: + return false; + } +} + +void MessageIter::copy_data( MessageIter& to ) +{ + for(MessageIter& from = *this; !from.at_end(); ++from) + { + if(is_basic_type(from.type())) + { + debug_log("copying basic type: %c", from.type()); + + unsigned char value[8]; + from.get_basic(from.type(), &value); + to.append_basic(from.type(), &value); + } + else + { + MessageIter from_container = from.recurse(); + char* sig = from_container.signature(); + + debug_log("copying compound type: %c[%s]", from.type(), sig); + + MessageIter to_container (to.msg()); + dbus_message_iter_open_container + ( + (DBusMessageIter*)&(to._iter), + from.type(), + from.type() == DBUS_TYPE_VARIANT ? NULL : sig, + (DBusMessageIter*)&(to_container._iter) + ); + + from_container.copy_data(to_container); + to.close_container(to_container); + free(sig); + } + } +} + +/* +*/ + +Message::Message() +: _pvt(new Private) +{ +} + +Message::Message( Message::Private* p, bool incref ) +: _pvt(p) +{ + if(_pvt->msg && incref) dbus_message_ref(_pvt->msg); +} + +Message::Message( const Message& m ) +: _pvt(m._pvt) +{ + dbus_message_ref(_pvt->msg); +} + +Message::~Message() +{ + dbus_message_unref(_pvt->msg); +} + +Message& Message::operator = ( const Message& m ) +{ + if(&m != this) + { + dbus_message_unref(_pvt->msg); + _pvt = m._pvt; + dbus_message_ref(_pvt->msg); + } + return *this; +} + +Message Message::copy() +{ + Private* pvt = new Private(dbus_message_copy(_pvt->msg)); + return Message(pvt); +} + +bool Message::append( int first_type, ... ) +{ + va_list vl; + va_start(vl, first_type); + + bool b = dbus_message_append_args_valist(_pvt->msg, first_type, vl); + + va_end(vl); + return b; +} + +void Message::terminate() +{ + dbus_message_append_args(_pvt->msg, DBUS_TYPE_INVALID); +} + +int Message::type() const +{ + return dbus_message_get_type(_pvt->msg); +} + +int Message::serial() const +{ + return dbus_message_get_serial(_pvt->msg); +} + +int Message::reply_serial() const +{ + return dbus_message_get_reply_serial(_pvt->msg); +} + +bool Message::reply_serial( int s ) +{ + return dbus_message_set_reply_serial(_pvt->msg, s); +} + +const char* Message::sender() const +{ + return dbus_message_get_sender(_pvt->msg); +} + +bool Message::sender( const char* s ) +{ + return dbus_message_set_sender(_pvt->msg, s); +} + +const char* Message::destination() const +{ + return dbus_message_get_destination(_pvt->msg); +} + +bool Message::destination( const char* s ) +{ + return dbus_message_set_destination(_pvt->msg, s); +} + +bool Message::is_error() const +{ + return type() == DBUS_MESSAGE_TYPE_ERROR; +} + +bool Message::is_signal( const char* interface, const char* member ) const +{ + return dbus_message_is_signal(_pvt->msg, interface, member); +} + +MessageIter Message::writer() +{ + MessageIter iter(*this); + dbus_message_iter_init_append(_pvt->msg, (DBusMessageIter*)&(iter._iter)); + return iter; +} + +MessageIter Message::reader() const +{ + MessageIter iter(const_cast(*this)); + dbus_message_iter_init(_pvt->msg, (DBusMessageIter*)&(iter._iter)); + return iter; +} + +/* +*/ + +ErrorMessage::ErrorMessage() +{ + _pvt->msg = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR); +} + +ErrorMessage::ErrorMessage( const Message& to_reply, const char* name, const char* message ) +{ + _pvt->msg = dbus_message_new_error(to_reply._pvt->msg, name, message); +} + +bool ErrorMessage::operator == ( const ErrorMessage& m ) const +{ + return dbus_message_is_error(_pvt->msg, m.name()); +} + +const char* ErrorMessage::name() const +{ + return dbus_message_get_error_name(_pvt->msg); +} + +bool ErrorMessage::name( const char* n ) +{ + return dbus_message_set_error_name(_pvt->msg, n); +} + +/* +*/ + +SignalMessage::SignalMessage( const char* name ) +{ + _pvt->msg = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); + member(name); +} + +SignalMessage::SignalMessage( const char* path, const char* interface, const char* name ) +{ + _pvt->msg = dbus_message_new_signal(path, interface, name); +} + +bool SignalMessage::operator == ( const SignalMessage& m ) const +{ + return dbus_message_is_signal(_pvt->msg, m.interface(), m.member()); +} + +const char* SignalMessage::interface() const +{ + return dbus_message_get_interface(_pvt->msg); +} + +bool SignalMessage::interface( const char* i ) +{ + return dbus_message_set_interface(_pvt->msg, i); +} + +const char* SignalMessage::member() const +{ + return dbus_message_get_member(_pvt->msg); +} + +bool SignalMessage::member( const char* m ) +{ + return dbus_message_set_member(_pvt->msg, m); +} + +const char* SignalMessage::path() const +{ + return dbus_message_get_path(_pvt->msg); +} + +char** SignalMessage::path_split() const +{ + char** p; + dbus_message_get_path_decomposed(_pvt->msg, &p); //todo: return as a std::vector ? + return p; +} + +bool SignalMessage::path( const char* p ) +{ + return dbus_message_set_path(_pvt->msg, p); +} + +/* +*/ + +CallMessage::CallMessage() +{ + _pvt->msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL); +} + +CallMessage::CallMessage( const char* dest, const char* path, const char* iface, const char* method ) +{ + _pvt->msg = dbus_message_new_method_call(dest, path, iface, method); +} + +bool CallMessage::operator == ( const CallMessage& m ) const +{ + return dbus_message_is_method_call(_pvt->msg, m.interface(), m.member()); +} + +const char* CallMessage::interface() const +{ + return dbus_message_get_interface(_pvt->msg); +} + +bool CallMessage::interface( const char* i ) +{ + return dbus_message_set_interface(_pvt->msg, i); +} + +const char* CallMessage::member() const +{ + return dbus_message_get_member(_pvt->msg); +} + +bool CallMessage::member( const char* m ) +{ + return dbus_message_set_member(_pvt->msg, m); +} + +const char* CallMessage::path() const +{ + return dbus_message_get_path(_pvt->msg); +} + +char** CallMessage::path_split() const +{ + char** p; + dbus_message_get_path_decomposed(_pvt->msg, &p); + return p; +} + +bool CallMessage::path( const char* p ) +{ + return dbus_message_set_path(_pvt->msg, p); +} + +const char* CallMessage::signature() const +{ + return dbus_message_get_signature(_pvt->msg); +} + +/* +*/ + +ReturnMessage::ReturnMessage( const CallMessage& callee ) +{ + _pvt = new Private(dbus_message_new_method_return(callee._pvt->msg)); +} + +const char* ReturnMessage::signature() const +{ + return dbus_message_get_signature(_pvt->msg); +} + Index: /tags/2.0-rc2/external/dbus/src/property.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/property.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/property.cpp (revision 562) @@ -0,0 +1,151 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + +#include +#include + +#include + +using namespace DBus; + +static const char* properties_name = "org.freedesktop.DBus.Properties"; + +PropertiesAdaptor::PropertiesAdaptor() +: InterfaceAdaptor(properties_name) +{ + register_method(PropertiesAdaptor, Get, Get); + register_method(PropertiesAdaptor, Set, Set); +} + +Message PropertiesAdaptor::Get( const CallMessage& call ) +{ + MessageIter ri = call.reader(); + + String iface_name; + String property_name; + + ri >> iface_name >> property_name; + + debug_log("requesting property %s on interface %s", property_name.c_str(), iface_name.c_str()); + + InterfaceAdaptor* interface = (InterfaceAdaptor*) find_interface(iface_name); + + if(!interface) + throw ErrorFailed("requested interface not found"); + + Variant* value = interface->get_property(property_name); + + if(!value) + throw ErrorFailed("requested property not found"); + + on_get_property(*interface, property_name, *value); + + ReturnMessage reply(call); + + MessageIter wi = reply.writer(); + + wi << *value; + return reply; +} + +Message PropertiesAdaptor::Set( const CallMessage& call ) +{ + MessageIter ri = call.reader(); + + String iface_name; + String property_name; + Variant value; + + ri >> iface_name >> property_name >> value; + + InterfaceAdaptor* interface = (InterfaceAdaptor*) find_interface(iface_name); + + if(!interface) + throw ErrorFailed("requested interface not found"); + + on_set_property(*interface, property_name, value); + + interface->set_property(property_name, value); + + ReturnMessage reply(call); + + return reply; +} + +IntrospectedInterface* const PropertiesAdaptor::introspect() const +{ + static IntrospectedArgument Get_args[] = + { + { "interface_name", "s", true }, + { "property_name", "s", true }, + { "value", "v", false }, + { 0, 0, 0 } + }; + static IntrospectedArgument Set_args[] = + { + { "interface_name", "s", true }, + { "property_name", "s", true }, + { "value", "v", true }, + { 0, 0, 0 } + }; + static IntrospectedMethod Properties_methods[] = + { + { "Get", Get_args }, + { "Set", Set_args }, + { 0, 0 } + }; + static IntrospectedMethod Properties_signals[] = + { + { 0, 0 } + }; + static IntrospectedProperty Properties_properties[] = + { + { 0, 0, 0, 0 } + }; + static IntrospectedInterface Properties_interface = + { + properties_name, + Properties_methods, + Properties_signals, + Properties_properties + }; + return &Properties_interface; +} + +PropertiesProxy::PropertiesProxy() +: InterfaceProxy(properties_name) +{ +} + +Variant PropertiesProxy::Get( const String& iface, const String& property ) +{ +//todo + Variant v; + return v; +} + +void PropertiesProxy::Set( const String& iface, const String& property, const Variant& value ) +{ +//todo +} + Index: /tags/2.0-rc2/external/dbus/src/dispatcher.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/dispatcher.cpp (revision 968) +++ /tags/2.0-rc2/external/dbus/src/dispatcher.cpp (revision 968) @@ -0,0 +1,241 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include + +#include + +#include "dispatcher_p.h" +#include "server_p.h" +#include "connection_p.h" + +DBus::Dispatcher* DBus::default_dispatcher = NULL; + +using namespace DBus; + +Timeout::Timeout( Timeout::Internal* i ) +: _int(i) +{ + dbus_timeout_set_data((DBusTimeout*)i, this, NULL); +} + +int Timeout::interval() const +{ + return dbus_timeout_get_interval((DBusTimeout*)_int); +} + +bool Timeout::enabled() const +{ + return dbus_timeout_get_enabled((DBusTimeout*)_int); +} + +bool Timeout::handle() +{ + return dbus_timeout_handle((DBusTimeout*)_int); +} + +/* +*/ + +Watch::Watch( Watch::Internal* i ) +: _int(i) +{ + dbus_watch_set_data((DBusWatch*)i, this, NULL); +} + +int Watch::descriptor() const +{ + return dbus_watch_get_fd((DBusWatch*)_int); +// return dbus_watch_get_unix_fd((DBusWatch*)_int); +} + +int Watch::flags() const +{ + return dbus_watch_get_flags((DBusWatch*)_int); +} + +bool Watch::enabled() const +{ + return dbus_watch_get_enabled((DBusWatch*)_int); +} + +bool Watch::handle( int flags ) +{ + return dbus_watch_handle((DBusWatch*)_int, flags); +} + +/* +*/ + +dbus_bool_t Dispatcher::Private::on_add_watch( DBusWatch* watch, void* data ) +{ + Dispatcher* d = static_cast(data); + + Watch::Internal* w = reinterpret_cast(watch); + + d->add_watch(w); + + return true; +} + +void Dispatcher::Private::on_rem_watch( DBusWatch* watch, void* data ) +{ + Dispatcher* d = static_cast(data); + + Watch* w = static_cast(dbus_watch_get_data(watch)); + + d->rem_watch(w); +} + +void Dispatcher::Private::on_toggle_watch( DBusWatch* watch, void* data ) +{ + Watch* w = static_cast(dbus_watch_get_data(watch)); + + w->toggle(); +} + +dbus_bool_t Dispatcher::Private::on_add_timeout( DBusTimeout* timeout, void* data ) +{ + Dispatcher* d = static_cast(data); + + Timeout::Internal* t = reinterpret_cast(timeout); + + d->add_timeout(t); + + return true; +} + +void Dispatcher::Private::on_rem_timeout( DBusTimeout* timeout, void* data ) +{ + Dispatcher* d = static_cast(data); + + Timeout* t = static_cast(dbus_timeout_get_data(timeout)); + + d->rem_timeout(t); +} + +void Dispatcher::Private::on_toggle_timeout( DBusTimeout* timeout, void* data ) +{ + Timeout* t = static_cast(dbus_timeout_get_data(timeout)); + + t->toggle(); +} + +void Dispatcher::queue_connection( Connection::Private* cp ) +{ + _pending_queue.push_back(cp); +} + +void Dispatcher::dispatch_pending() +{ + while(_pending_queue.size() > 0) + { + Connection::PrivatePList::iterator i, j; + + i = _pending_queue.begin(); + + while(i != _pending_queue.end()) + { + j = i; + + ++j; + + if((*i)->do_dispatch()) + _pending_queue.erase(i); + + i = j; + } + } +} + +#ifdef DBUS_HAS_THREADS_INIT_DEFAULT +void DBus::_init_threading() +{ + dbus_threads_init_default(); +} +#endif//DBUS_HAS_THREADS_INIT_DEFAULT + +void DBus::_init_threading( + MutexNewFn m1, + MutexFreeFn m2, + MutexLockFn m3, + MutexUnlockFn m4, + CondVarNewFn c1, + CondVarFreeFn c2, + CondVarWaitFn c3, + CondVarWaitTimeoutFn c4, + CondVarWakeOneFn c5, + CondVarWakeAllFn c6 +) +{ +#ifndef DBUS_HAS_RECURSIVE_MUTEX + DBusThreadFunctions functions = { + DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK | + DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK | + DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK | + DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK| + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK, + (DBusMutexNewFunction) m1, + (DBusMutexFreeFunction) m2, + (DBusMutexLockFunction) m3, + (DBusMutexUnlockFunction) m4, + (DBusCondVarNewFunction) c1, + (DBusCondVarFreeFunction) c2, + (DBusCondVarWaitFunction) c3, + (DBusCondVarWaitTimeoutFunction) c4, + (DBusCondVarWakeOneFunction) c5, + (DBusCondVarWakeAllFunction) c6 + }; +#else + DBusThreadFunctions functions = { + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK | + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK | + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK | + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK| + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK, + 0, 0, 0, 0, + (DBusCondVarNewFunction) c1, + (DBusCondVarFreeFunction) c2, + (DBusCondVarWaitFunction) c3, + (DBusCondVarWaitTimeoutFunction) c4, + (DBusCondVarWakeOneFunction) c5, + (DBusCondVarWakeAllFunction) c6, + (DBusRecursiveMutexNewFunction) m1, + (DBusRecursiveMutexFreeFunction) m2, + (DBusRecursiveMutexLockFunction) m3, + (DBusRecursiveMutexUnlockFunction) m4 + }; +#endif//DBUS_HAS_RECURSIVE_MUTEX + dbus_threads_init(&functions); +} Index: /tags/2.0-rc2/external/dbus/src/debug.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/debug.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/debug.cpp (revision 562) @@ -0,0 +1,55 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include + +#include +#include +#include + +static void _debug_log_default(const char* format, ...) +{ +#ifdef DEBUG + + static int debug_env = -1; + + if(debug_env < 0) debug_env = getenv("DBUSXX_VERBOSE") ? 1 : 0; + + if(debug_env) + { + va_list args; + va_start(args, format); + + fprintf(stderr, "dbus-c++: "); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + + va_end(args); + } + +#endif//DEBUG +} + +DBus::LogFunction DBus::debug_log = _debug_log_default; + Index: /tags/2.0-rc2/external/dbus/src/error.cpp =================================================================== --- /tags/2.0-rc2/external/dbus/src/error.cpp (revision 562) +++ /tags/2.0-rc2/external/dbus/src/error.cpp (revision 562) @@ -0,0 +1,86 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#include +#include + +#include + +#include "message_p.h" +#include "internalerror.h" + +using namespace DBus; + +/* +*/ + +Error::Error() +: _int(new InternalError) +{} + +Error::Error(InternalError& i) +: _int(new InternalError(i)) +{} + +Error::Error( const char* name, const char* message ) +: _int(new InternalError) +{ + set(name, message); +} + +Error::Error( Message& m ) +: _int(new InternalError) +{ + dbus_set_error_from_message(&(_int->error), m._pvt->msg); +} + +Error::~Error() throw() +{ +} + +const char* Error::name() const +{ + return _int->error.name; +} + +const char* Error::message() const +{ + return _int->error.message; +} + +bool Error::is_set() const +{ + return *(_int); +} + +void Error::set( const char* name, const char* message ) +{ + dbus_set_error_const(&(_int->error), name, message); +} + +const char* Error::what() const throw() +{ + return _int->error.message; +} + Index: /tags/2.0-rc2/external/dbus/src/server_p.h =================================================================== --- /tags/2.0-rc2/external/dbus/src/server_p.h (revision 562) +++ /tags/2.0-rc2/external/dbus/src/server_p.h (revision 562) @@ -0,0 +1,57 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_SERVER_P_H +#define __DBUSXX_SERVER_P_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include + +namespace DBus { + +struct DXXAPILOCAL Server::Private +{ + DBusServer* server; + + Dispatcher* dispatcher; + + ConnectionList connections; + + Private( DBusServer* ); + + ~Private(); + + static void on_new_conn_cb( DBusServer* server, DBusConnection* conn, void* data ); +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_SERVER_P_H Index: /tags/2.0-rc2/external/dbus/src/internalerror.h =================================================================== --- /tags/2.0-rc2/external/dbus/src/internalerror.h (revision 562) +++ /tags/2.0-rc2/external/dbus/src/internalerror.h (revision 562) @@ -0,0 +1,77 @@ +/* + * + * D-Bus++ - C++ bindings for D-Bus + * + * Copyright (C) 2005-2007 Paolo Durante + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * + */ + + +#ifndef __DBUSXX_INTERNALERROR_H +#define __DBUSXX_INTERNALERROR_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +namespace DBus { + +struct DXXAPI InternalError +{ + DBusError error; + + InternalError() + { + dbus_error_init(&error); + } + + explicit InternalError( DBusError* e ) + { + dbus_error_init(&error); + dbus_move_error(e, &error); + } + + InternalError(const InternalError& ie) + { + dbus_error_init(&error); + dbus_move_error(const_cast(&(ie.error)), &error); + } + + ~InternalError() + { + dbus_error_free(&error); + } + + operator DBusError*() + { + return &error; + } + + operator bool() + { + return dbus_error_is_set(&error); + } +}; + +} /* namespace DBus */ + +#endif//__DBUSXX_INTERNALERROR_H Index: /tags/2.0-rc2/external/dbus/README =================================================================== --- /tags/2.0-rc2/external/dbus/README (revision 562) +++ /tags/2.0-rc2/external/dbus/README (revision 562) @@ -0,0 +1,2 @@ +DBUS C++ Bindings copied from: +http://dev.openwengo.org/svn/openwengo/wengophone-ng/branches/wengophone-dbus-api/libs/dbus Index: /tags/2.0-rc2/AUTHORS =================================================================== --- /tags/2.0-rc2/AUTHORS (revision 742) +++ /tags/2.0-rc2/AUTHORS (revision 742) @@ -0,0 +1,4 @@ +Daniel Wagner +Pieter Palmers +Jonathan Woithe +Arnold Krille Index: /tags/2.0-rc2/src/libieee1394/CycleTimerHelper.cpp =================================================================== --- /tags/2.0-rc2/src/libieee1394/CycleTimerHelper.cpp (revision 1544) +++ /tags/2.0-rc2/src/libieee1394/CycleTimerHelper.cpp (revision 1544) @@ -0,0 +1,824 @@ +/* + * 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 . + * + */ + +#include "config.h" + +#include "CycleTimerHelper.h" +#include "ieee1394service.h" +#include "libutil/PosixThread.h" +#include "libutil/PosixMutex.h" +#include "libutil/Atomic.h" +#include "libutil/Watchdog.h" + +#define DLL_PI (3.141592653589793238) +#define DLL_2PI (2 * DLL_PI) +#define DLL_SQRT2 (1.414213562373095049) + +IMPL_DEBUG_MODULE( CycleTimerHelper, CycleTimerHelper, DEBUG_LEVEL_NORMAL ); + +CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us) + : m_Parent ( parent ) + , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL ) + , m_usecs_per_update ( update_period_us ) + , m_avg_wakeup_delay ( 0.0 ) + , m_dll_e2 ( 0.0 ) + , m_current_time_usecs ( 0 ) + , m_next_time_usecs ( 0 ) + , m_current_time_ticks ( 0 ) + , m_next_time_ticks ( 0 ) + , m_first_run ( true ) + , m_sleep_until ( 0 ) + , m_cycle_timer_prev ( 0 ) + , m_cycle_timer_ticks_prev ( 0 ) + , m_current_shadow_idx ( 0 ) + , m_Thread ( NULL ) + , m_realtime ( false ) + , m_priority ( 0 ) + , m_update_lock( new Util::PosixMutex("CTRUPD") ) + , m_busreset_functor ( NULL) + , m_unhandled_busreset ( false ) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this); + + double bw_rel = IEEE1394SERVICE_CYCLETIMER_DLL_BANDWIDTH_HZ*((double)update_period_us)/1e6; + m_dll_coeff_b = bw_rel * (DLL_SQRT2 * DLL_2PI); + m_dll_coeff_c = bw_rel * bw_rel * DLL_2PI * DLL_2PI; + +} + +CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us, bool rt, int prio) + : m_Parent ( parent ) + , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL ) + , m_usecs_per_update ( update_period_us ) + , m_avg_wakeup_delay ( 0.0 ) + , m_dll_e2 ( 0.0 ) + , m_current_time_usecs ( 0 ) + , m_next_time_usecs ( 0 ) + , m_current_time_ticks ( 0 ) + , m_next_time_ticks ( 0 ) + , m_first_run ( true ) + , m_sleep_until ( 0 ) + , m_cycle_timer_prev ( 0 ) + , m_cycle_timer_ticks_prev ( 0 ) + , m_current_shadow_idx ( 0 ) + , m_Thread ( NULL ) + , m_realtime ( rt ) + , m_priority ( prio ) + , m_update_lock( new Util::PosixMutex("CTRUPD") ) + , m_busreset_functor ( NULL) + , m_unhandled_busreset ( false ) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this); + + double bw_rel = IEEE1394SERVICE_CYCLETIMER_DLL_BANDWIDTH_HZ*((double)update_period_us)/1e6; + m_dll_coeff_b = bw_rel * (DLL_SQRT2 * DLL_2PI); + m_dll_coeff_c = bw_rel * bw_rel * DLL_2PI * DLL_2PI; +} + +CycleTimerHelper::~CycleTimerHelper() +{ + if (m_Thread) { + m_Thread->Stop(); + delete m_Thread; + } + + // unregister the bus reset handler + if(m_busreset_functor) { + m_Parent.remBusResetHandler( m_busreset_functor ); + delete m_busreset_functor; + } + delete m_update_lock; +} + +bool +CycleTimerHelper::Start() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Start %p...\n", this); + + if(!initValues()) { + debugFatal("(%p) Could not init values\n", this); + return false; + } + + m_Thread = new Util::PosixThread(this, "CTRHLP", m_realtime, m_priority, + PTHREAD_CANCEL_DEFERRED); + if(!m_Thread) { + debugFatal("No thread\n"); + return false; + } + // register the thread with the RT watchdog + Util::Watchdog *watchdog = m_Parent.getWatchdog(); + if(watchdog) { + if(!watchdog->registerThread(m_Thread)) { + debugWarning("could not register update thread with watchdog\n"); + } + } else { + debugWarning("could not find valid watchdog\n"); + } + + if (m_Thread->Start() != 0) { + debugFatal("Could not start update thread\n"); + return false; + } + return true; +} + +bool +CycleTimerHelper::initValues() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) Init values...\n", this ); + Util::MutexLockHelper lock(*m_update_lock); + + // initialize the 'prev ctr' values + uint64_t local_time; + int maxtries2 = 10; + do { + debugOutput( DEBUG_LEVEL_VERBOSE, "Read CTR...\n" ); + if(!m_Parent.readCycleTimerReg(&m_cycle_timer_prev, &local_time)) { + debugError("Could not read cycle timer register\n"); + return false; + } + if (m_cycle_timer_prev == 0) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "Bogus CTR: %08X on try %02d\n", + m_cycle_timer_prev, maxtries2); + } + debugOutput( DEBUG_LEVEL_VERBOSE, " read : CTR: %11lu, local: %17llu\n", + m_cycle_timer_prev, local_time); + debugOutput(DEBUG_LEVEL_VERBOSE, + " ctr : 0x%08X %11llu (%03us %04ucy %04uticks)\n", + (uint32_t)m_cycle_timer_prev, (uint64_t)CYCLE_TIMER_TO_TICKS(m_cycle_timer_prev), + (unsigned int)CYCLE_TIMER_GET_SECS( m_cycle_timer_prev ), + (unsigned int)CYCLE_TIMER_GET_CYCLES( m_cycle_timer_prev ), + (unsigned int)CYCLE_TIMER_GET_OFFSET( m_cycle_timer_prev ) ); + + } while (m_cycle_timer_prev == 0 && maxtries2--); + m_cycle_timer_ticks_prev = CYCLE_TIMER_TO_TICKS(m_cycle_timer_prev); + +#if IEEE1394SERVICE_USE_CYCLETIMER_DLL + debugOutput( DEBUG_LEVEL_VERBOSE, "requesting DLL re-init...\n" ); + Util::SystemTimeSource::SleepUsecRelative(1000); // some time to settle + if(!initDLL()) { + debugError("(%p) Could not init DLL\n", this); + return false; + } + // make the DLL re-init itself as if it were started up + m_first_run = true; +#endif + debugOutput( DEBUG_LEVEL_VERBOSE, "ready...\n" ); + return true; +} + +bool +CycleTimerHelper::Init() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Initialize %p...\n", this); + + // register a bus reset handler + m_busreset_functor = new Util::MemberFunctor0< CycleTimerHelper*, + void (CycleTimerHelper::*)() > + ( this, &CycleTimerHelper::busresetHandler, false ); + if ( !m_busreset_functor ) { + debugFatal( "(%p) Could not create busreset handler\n", this ); + return false; + } + m_Parent.addBusResetHandler( m_busreset_functor ); + + #ifdef DEBUG + m_last_loop_entry = 0; + m_successive_short_loops = 0; + #endif + + return true; +} + +void +CycleTimerHelper::busresetHandler() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Bus reset...\n" ); + m_unhandled_busreset = true; + // whenever a bus reset occurs, the root node can change, + // and the CTR timer can be reset. We should hence reinit + // the DLL + if(!initValues()) { + debugError("(%p) Could not re-init values\n", this); + } + m_unhandled_busreset = false; +} + +bool +CycleTimerHelper::setThreadParameters(bool rt, int priority) { + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority); + if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority + m_realtime = rt; + m_priority = priority; + +#if IEEE1394SERVICE_USE_CYCLETIMER_DLL + if (m_Thread) { + if (m_realtime) { + m_Thread->AcquireRealTime(m_priority); + } else { + m_Thread->DropRealTime(); + } + } +#endif + + return true; +} + +#if IEEE1394SERVICE_USE_CYCLETIMER_DLL +float +CycleTimerHelper::getRate() +{ + float rate = (float)(diffTicks((uint64_t)m_next_time_ticks, (uint64_t)m_current_time_ticks)); + rate /= (float)(m_next_time_usecs - m_current_time_usecs); + return rate; +} + +float +CycleTimerHelper::getNominalRate() +{ + float rate = ((double)TICKS_PER_SECOND) / 1000000.0; + return rate; +} + +/* + * call with lock held + */ +bool +CycleTimerHelper::initDLL() { + uint32_t cycle_timer; + uint64_t local_time; + uint64_t cycle_timer_ticks; + + double bw_rel = m_dll_coeff_b / (DLL_SQRT2 * DLL_2PI); + double bw_abs = bw_rel / (m_usecs_per_update / 1e6); + if (bw_rel > 0.5) { + double bw_max = 0.5 / (m_usecs_per_update / 1e6); + debugWarning("Specified DLL bandwidth too high (%f > %f), reducing to max." + " Increase the DLL update rate to increase the max DLL bandwidth\n", bw_abs, bw_max); + + bw_rel = 0.49; + bw_abs = bw_rel / (m_usecs_per_update / 1e6); + m_dll_coeff_b = bw_rel * (DLL_SQRT2 * DLL_2PI); + m_dll_coeff_c = bw_rel * bw_rel * DLL_2PI * DLL_2PI; + } + + if(!readCycleTimerWithRetry(&cycle_timer, &local_time, 10)) { + debugError("Could not read cycle timer register\n"); + return false; + } + cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer); + + debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, " read : CTR: %11lu, local: %17llu\n", + cycle_timer, local_time); + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + " ctr : 0x%08X %11llu (%03us %04ucy %04uticks)\n", + (uint32_t)cycle_timer, (uint64_t)cycle_timer_ticks, + (unsigned int)TICKS_TO_SECS( (uint64_t)cycle_timer_ticks ), + (unsigned int)TICKS_TO_CYCLES( (uint64_t)cycle_timer_ticks ), + (unsigned int)TICKS_TO_OFFSET( (uint64_t)cycle_timer_ticks ) ); + + m_sleep_until = local_time + m_usecs_per_update; + m_dll_e2 = m_ticks_per_update; + m_current_time_usecs = local_time; + m_next_time_usecs = m_current_time_usecs + m_usecs_per_update; + m_current_time_ticks = CYCLE_TIMER_TO_TICKS( cycle_timer ); + m_next_time_ticks = addTicks( (uint64_t)m_current_time_ticks, (uint64_t)m_dll_e2); + debugOutput(DEBUG_LEVEL_VERBOSE, " (%p) First run\n", this); + debugOutput(DEBUG_LEVEL_VERBOSE, " DLL bandwidth: %f Hz (rel: %f)\n", + bw_abs, bw_rel); + debugOutput(DEBUG_LEVEL_VERBOSE, + " usecs/update: %lu, ticks/update: %lu, m_dll_e2: %f\n", + m_usecs_per_update, m_ticks_per_update, m_dll_e2); + debugOutput(DEBUG_LEVEL_VERBOSE, + " usecs current: %f, next: %f\n", + m_current_time_usecs, m_next_time_usecs); + debugOutput(DEBUG_LEVEL_VERBOSE, + " ticks current: %f, next: %f\n", + m_current_time_ticks, m_next_time_ticks); + return true; +} + +bool +CycleTimerHelper::Execute() +{ + debugOutput( DEBUG_LEVEL_ULTRA_VERBOSE, "Execute %p...\n", this); + + #ifdef DEBUG + uint64_t now = m_Parent.getCurrentTimeAsUsecs(); + int diff = now - m_last_loop_entry; + if(diff < 100) { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "(%p) short loop detected (%d usec), cnt: %d\n", + this, diff, m_successive_short_loops); + m_successive_short_loops++; + if(m_successive_short_loops > 100) { + debugError("Shutting down runaway thread\n"); + return false; + } + } else { + // reset the counter + m_successive_short_loops = 0; + } + m_last_loop_entry = now; + #endif + + if (!m_first_run) { + // wait for the next update period + //#if DEBUG_EXTREME_ENABLE + #ifdef DEBUG + ffado_microsecs_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs(); + int sleep_time = m_sleep_until - now; + debugOutput( DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) Sleep until %lld/%f (now: %lld, diff=%d) ...\n", + this, m_sleep_until, m_next_time_usecs, now, sleep_time); + #endif + Util::SystemTimeSource::SleepUsecAbsolute(m_sleep_until); + debugOutput( DEBUG_LEVEL_ULTRA_VERBOSE, " (%p) back...\n", this); + } + + uint32_t cycle_timer; + uint64_t local_time; + int64_t usecs_late; + int ntries=10; + uint64_t cycle_timer_ticks; + int64_t err_ticks; + bool not_good; + + // if the difference between the predicted value at readout time and the + // actual value seems to be too large, retry reading the cycle timer + // some host controllers return bogus values on some reads + // (looks like a non-atomic update of the register) + do { + debugOutput( DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) reading cycle timer register...\n", this); + if(!readCycleTimerWithRetry(&cycle_timer, &local_time, 10)) { + debugError("Could not read cycle timer register\n"); + return false; + } + usecs_late = local_time - m_sleep_until; + cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer); + + // calculate the CTR_TICKS we expect to read at "local_time" + // then calculate the difference with what we actually read, + // taking wraparound into account. If these deviate too much + // from eachother then read the register again (bogus read). + int64_t expected_ticks = getCycleTimerTicks(local_time); + err_ticks = diffTicks(cycle_timer_ticks, expected_ticks); + + // check for unrealistic CTR reads (NEC controller does that sometimes) + not_good = (-err_ticks > 1*TICKS_PER_CYCLE || err_ticks > 1*TICKS_PER_CYCLE); + if(not_good) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) have to retry CTR read, diff unrealistic: diff: %lld, max: +/- %u (try: %d) %lld\n", + this, err_ticks, 1*TICKS_PER_CYCLE, ntries, expected_ticks); + // sleep half a cycle to make sure the hardware moved on + Util::SystemTimeSource::SleepUsecRelative(USECS_PER_CYCLE / 2); + } + + } while(not_good && --ntries && !m_first_run && !m_unhandled_busreset); + + // grab the lock after sleeping, otherwise we can't be interrupted by + // the busreset thread (lower prio) + // also grab it after reading the CTR register such that the jitter between + // wakeup and read is as small as possible + Util::MutexLockHelper lock(*m_update_lock); + + // the difference between the measured and the expected time + int64_t diff_ticks = diffTicks(cycle_timer_ticks, (int64_t)m_next_time_ticks); + + // // simulate a random scheduling delay between (0-10ms) + // ffado_microsecs_t tmp = Util::SystemTimeSource::SleepUsecRandom(10000); + // debugOutput( DEBUG_LEVEL_VERBOSE, " (%p) random sleep of %llu usecs...\n", this, tmp); + + if(m_unhandled_busreset) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) Skipping DLL update due to unhandled busreset\n", this); + m_sleep_until += m_usecs_per_update; + // keep the thread running + return true; + } + + debugOutputExtreme( DEBUG_LEVEL_ULTRA_VERBOSE, " read : CTR: %11lu, local: %17llu\n", + cycle_timer, local_time); + debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, + " ctr : 0x%08X %11llu (%03us %04ucy %04uticks)\n", + (uint32_t)cycle_timer, (uint64_t)cycle_timer_ticks, + (unsigned int)TICKS_TO_SECS( (uint64_t)cycle_timer_ticks ), + (unsigned int)TICKS_TO_CYCLES( (uint64_t)cycle_timer_ticks ), + (unsigned int)TICKS_TO_OFFSET( (uint64_t)cycle_timer_ticks ) ); + + if (m_first_run) { + if(!initDLL()) { + debugError("(%p) Could not init DLL\n", this); + return false; + } + m_first_run = false; + } else if (diff_ticks > m_ticks_per_update * 20) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "re-init dll due to too large tick diff: %lld >> %f\n", + diff_ticks, (float)(m_ticks_per_update * 20)); + if(!initDLL()) { + debugError("(%p) Could not init DLL\n", this); + return false; + } + } else { + // calculate next sleep time + m_sleep_until += m_usecs_per_update; + + // correct for the latency between the wakeup and the actual CTR + // read. The only time we can trust is the time returned by the + // CTR read kernel call, since that (should be) atomically read + // together with the ctr register itself. + + // if we are usecs_late usecs late + // the cycle timer has ticked approx ticks_late ticks too much + // if we are woken up early (which shouldn't happen according to POSIX) + // the cycle timer has ticked approx -ticks_late too little + int64_t ticks_late = (usecs_late * TICKS_PER_SECOND) / 1000000LL; + // the corrected difference between predicted and actual ctr + // i.e. DLL error signal + int64_t diff_ticks_corr; + if (ticks_late >= 0) { + diff_ticks_corr = diff_ticks - ticks_late; + debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, + "diff_ticks_corr=%lld, diff_ticks = %lld, ticks_late = %lld\n", + diff_ticks_corr, diff_ticks, ticks_late); + } else { + debugError("Early wakeup, should not happen!\n"); + // recover + diff_ticks_corr = diff_ticks + ticks_late; + } + + #ifdef DEBUG + // makes no sense if not running realtime + if(m_realtime && usecs_late > 1000) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Rather late wakeup: %lld usecs\n", usecs_late); + } + #endif + + // update the x-axis values + m_current_time_ticks = m_next_time_ticks; + + // decide what coefficients to use + + // it should be ok to not do this in tick space + // since diff_ticks_corr should not be near wrapping + // (otherwise we are out of range. we need a few calls + // w/o wrapping for this to work. That should not be + // an issue as long as the update interval is smaller + // than the wrapping interval.) + // and coeff_b < 1, hence tmp is not near wrapping + + double diff_ticks_corr_d = (double)diff_ticks_corr; + double step_ticks = (m_dll_coeff_b * diff_ticks_corr_d); + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "diff_ticks_corr=%f, step_ticks=%f\n", + diff_ticks_corr_d, step_ticks); + + // the same goes for m_dll_e2, which should be approx equal + // to the ticks/usec rate (= 24.576) hence also not near + // wrapping + step_ticks += m_dll_e2; + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "add %f ticks to step_ticks => step_ticks=%f\n", + m_dll_e2, step_ticks); + + // it can't be that we have to update to a value in the past + if(step_ticks < 0) { + debugError("negative step: %f! (correcting to nominal)\n", step_ticks); + // recover to an estimated value + step_ticks = (double)m_ticks_per_update; + } + + if(step_ticks > TICKS_PER_SECOND) { + debugWarning("rather large step: %f ticks (> 1sec)\n", step_ticks); + } + + // now add the step ticks with wrapping. + m_next_time_ticks = (double)(addTicks((uint64_t)m_current_time_ticks, (uint64_t)step_ticks)); + + // update the DLL state + m_dll_e2 += m_dll_coeff_c * diff_ticks_corr_d; + + // update the y-axis values + m_current_time_usecs = m_next_time_usecs; + m_next_time_usecs += m_usecs_per_update; + + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + " usecs: current: %f next: %f usecs_late=%lld ticks_late=%lld\n", + m_current_time_usecs, m_next_time_usecs, usecs_late, ticks_late); + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + " ticks: current: %f next: %f diff=%lld\n", + m_current_time_ticks, m_next_time_ticks, diff_ticks); + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + " ticks: current: %011llu (%03us %04ucy %04uticks)\n", + (uint64_t)m_current_time_ticks, + (unsigned int)TICKS_TO_SECS( (uint64_t)m_current_time_ticks ), + (unsigned int)TICKS_TO_CYCLES( (uint64_t)m_current_time_ticks ), + (unsigned int)TICKS_TO_OFFSET( (uint64_t)m_current_time_ticks ) ); + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + " ticks: next : %011llu (%03us %04ucy %04uticks)\n", + (uint64_t)m_next_time_ticks, + (unsigned int)TICKS_TO_SECS( (uint64_t)m_next_time_ticks ), + (unsigned int)TICKS_TO_CYCLES( (uint64_t)m_next_time_ticks ), + (unsigned int)TICKS_TO_OFFSET( (uint64_t)m_next_time_ticks ) ); + + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + " state: local: %11llu, dll_e2: %f, rate: %f\n", + local_time, m_dll_e2, getRate()); + } + + // prepare the new compute vars + struct compute_vars new_vars; + new_vars.ticks = (uint64_t)(m_current_time_ticks); + new_vars.usecs = (uint64_t)m_current_time_usecs; + new_vars.rate = getRate(); + + // get the next index + unsigned int next_idx = (m_current_shadow_idx + 1) % CTRHELPER_NB_SHADOW_VARS; + + // update the next index position + m_shadow_vars[next_idx] = new_vars; + + // then we can update the current index + m_current_shadow_idx = next_idx; + +#ifdef DEBUG + // do some verification + // we re-read a valid ctr timestamp + // then we use the attached system time to calculate + // the DLL generated timestamp and we check what the + // difference is + + if(!readCycleTimerWithRetry(&cycle_timer, &local_time, 10)) { + debugError("Could not read cycle timer register (verify)\n"); + return true; // true since this is a check only + } + cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer); + + // only check when successful + int64_t time_diff = local_time - new_vars.usecs; + double y_step_in_ticks = ((double)time_diff) * new_vars.rate; + int64_t y_step_in_ticks_int = (int64_t)y_step_in_ticks; + uint64_t offset_in_ticks_int = new_vars.ticks; + uint32_t dll_time; + if (y_step_in_ticks_int > 0) { + dll_time = addTicks(offset_in_ticks_int, y_step_in_ticks_int); + } else { + dll_time = substractTicks(offset_in_ticks_int, -y_step_in_ticks_int); + } + int32_t ctr_diff = cycle_timer_ticks-dll_time; + debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, "(%p) CTR DIFF: HW %010llu - DLL %010lu = %010ld (%s)\n", + this, cycle_timer_ticks, dll_time, ctr_diff, (ctr_diff>0?"lag":"lead")); +#endif + + return true; +} + +uint32_t +CycleTimerHelper::getCycleTimerTicks() +{ + uint64_t now = m_Parent.getCurrentTimeAsUsecs(); + return getCycleTimerTicks(now); +} + +uint32_t +CycleTimerHelper::getCycleTimerTicks(uint64_t now) +{ + uint32_t retval; + struct compute_vars *my_vars; + + // get pointer and copy the contents + // no locking should be needed since we have more than one + // of these vars available, and our use will always be finished before + // m_current_shadow_idx changes since this thread's priority should + // be higher than the one of the writer thread. Even if not, we only have to ensure + // that the used dataset is consistent. We can use an older dataset if it's consistent + // since it will also provide a fairly decent extrapolation. + my_vars = m_shadow_vars + m_current_shadow_idx; + + int64_t time_diff = now - my_vars->usecs; + double y_step_in_ticks = ((double)time_diff) * my_vars->rate; + int64_t y_step_in_ticks_int = (int64_t)y_step_in_ticks; + uint64_t offset_in_ticks_int = my_vars->ticks; + + if (y_step_in_ticks_int > 0) { + retval = addTicks(offset_in_ticks_int, y_step_in_ticks_int); +/* debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "y_step_in_ticks_int > 0: %lld, time_diff: %f, rate: %f, retval: %lu\n", + y_step_in_ticks_int, time_diff, my_vars.rate, retval);*/ + } else { + retval = substractTicks(offset_in_ticks_int, -y_step_in_ticks_int); + + // this can happen if the update thread was woken up earlier than it should have been +/* debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "y_step_in_ticks_int <= 0: %lld, time_diff: %f, rate: %f, retval: %lu\n", + y_step_in_ticks_int, time_diff, my_vars.rate, retval);*/ + } + + return retval; +} + +uint32_t +CycleTimerHelper::getCycleTimer() +{ + uint64_t now = m_Parent.getCurrentTimeAsUsecs(); + return getCycleTimer(now); +} + +uint32_t +CycleTimerHelper::getCycleTimer(uint64_t now) +{ + uint32_t ticks = getCycleTimerTicks(now); + uint32_t result = TICKS_TO_CYCLE_TIMER(ticks); +#ifdef DEBUG + if(CYCLE_TIMER_TO_TICKS(result) != ticks) { + debugWarning("Bad ctr conversion"); + } +#endif + return result; +} + +uint64_t +CycleTimerHelper::getSystemTimeForCycleTimerTicks(uint32_t ticks) +{ + uint64_t retval; + struct compute_vars *my_vars; + + // get pointer and copy the contents + // no locking should be needed since we have more than one + // of these vars available, and our use will always be finished before + // m_current_shadow_idx changes since this thread's priority should + // be higher than the one of the writer thread. Even if not, we only have to ensure + // that the used dataset is consistent. We can use an older dataset if it's consistent + // since it will also provide a fairly decent extrapolation. + my_vars = m_shadow_vars + m_current_shadow_idx; + + // the number of ticks the request is ahead of the current CTR position + int64_t ticks_diff = diffTicks(ticks, my_vars->ticks); + // to how much time does this correspond? + double x_step_in_usec = ((double)ticks_diff) / my_vars->rate; + int64_t x_step_in_usec_int = (int64_t)x_step_in_usec; + retval = my_vars->usecs + x_step_in_usec_int; + + return retval; +} + +uint64_t +CycleTimerHelper::getSystemTimeForCycleTimer(uint32_t ctr) +{ + uint32_t ticks = CYCLE_TIMER_TO_TICKS(ctr); + return getSystemTimeForCycleTimerTicks(ticks); +} + +#else + +float +CycleTimerHelper::getRate() +{ + return getNominalRate(); +} + +float +CycleTimerHelper::getNominalRate() +{ + float rate = ((double)TICKS_PER_SECOND) / 1000000.0; + return rate; +} + +bool +CycleTimerHelper::Execute() +{ + usleep(1000*1000); + return true; +} + +uint32_t +CycleTimerHelper::getCycleTimerTicks() +{ + return CYCLE_TIMER_TO_TICKS(getCycleTimer()); +} + +uint32_t +CycleTimerHelper::getCycleTimerTicks(uint64_t now) +{ + debugWarning("untested code\n"); + #warning Untested code + uint32_t cycle_timer; + uint64_t local_time; + readCycleTimerWithRetry(&cycle_timer, &local_time, 10); + int64_t ticks = CYCLE_TIMER_TO_TICKS(cycle_timer); + + int delta_t = now - local_time; // how far ahead is the request? + ticks += delta_t * getRate(); // add ticks + if (ticks >= TICKS_PER_SECOND * 128) ticks -= TICKS_PER_SECOND * 128; + else if (ticks < 0) ticks += TICKS_PER_SECOND * 128; + return ticks; +} + +uint32_t +CycleTimerHelper::getCycleTimer() +{ + uint32_t cycle_timer; + uint64_t local_time; + readCycleTimerWithRetry(&cycle_timer, &local_time, 10); + return cycle_timer; +} + +uint32_t +CycleTimerHelper::getCycleTimer(uint64_t now) +{ + return TICKS_TO_CYCLE_TIMER(getCycleTimerTicks(now)); +} + +uint64_t +CycleTimerHelper::getSystemTimeForCycleTimerTicks(uint32_t ticks) +{ + debugWarning("not implemented!\n"); + return 0; +} + +uint64_t +CycleTimerHelper::getSystemTimeForCycleTimer(uint32_t ctr) +{ + uint32_t ticks = CYCLE_TIMER_TO_TICKS(ctr); + return getSystemTimeForCycleTimerTicks(ticks); +} + +#endif + +bool +CycleTimerHelper::readCycleTimerWithRetry(uint32_t *cycle_timer, uint64_t *local_time, int ntries) +{ + bool good=false; + int maxtries = ntries; + + do { + // the ctr read can return 0 sometimes. if that happens, reread the ctr. + int maxtries2=ntries; + do { + if(!m_Parent.readCycleTimerReg(cycle_timer, local_time)) { + debugError("Could not read cycle timer register\n"); + return false; + } + if (*cycle_timer == 0) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "Bogus CTR: %08X on try %02d\n", + *cycle_timer, maxtries2); + } + } while (*cycle_timer == 0 && maxtries2--); + + // catch bogus ctr reads (can happen) + uint64_t cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(*cycle_timer); + + if (diffTicks(cycle_timer_ticks, m_cycle_timer_ticks_prev) < 0) { + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, + "non-monotonic CTR (try %02d): %llu -> %llu\n", + maxtries, m_cycle_timer_ticks_prev, cycle_timer_ticks); + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, + " : %08X -> %08X\n", + m_cycle_timer_prev, *cycle_timer); + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, + " current: %011llu (%03us %04ucy %04uticks)\n", + cycle_timer_ticks, + (unsigned int)TICKS_TO_SECS( cycle_timer_ticks ), + (unsigned int)TICKS_TO_CYCLES( cycle_timer_ticks ), + (unsigned int)TICKS_TO_OFFSET( cycle_timer_ticks ) ); + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, + " prev : %011llu (%03us %04ucy %04uticks)\n", + m_cycle_timer_ticks_prev, + (unsigned int)TICKS_TO_SECS( m_cycle_timer_ticks_prev ), + (unsigned int)TICKS_TO_CYCLES( m_cycle_timer_ticks_prev ), + (unsigned int)TICKS_TO_OFFSET( m_cycle_timer_ticks_prev ) ); + } else { + good = true; + m_cycle_timer_prev = *cycle_timer; + m_cycle_timer_ticks_prev = cycle_timer_ticks; + } + } while (!good && maxtries--); + return true; +} + +void +CycleTimerHelper::setVerboseLevel(int l) +{ + setDebugLevel(l); +} Index: /tags/2.0-rc2/src/libieee1394/csr1212.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/csr1212.h (revision 864) +++ /tags/2.0-rc2/src/libieee1394/csr1212.h (revision 864) @@ -0,0 +1,754 @@ +/* + * 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 . + * + */ +/* + * csr1212.h -- IEEE 1212 Control and Status Register support for Linux + * + * Copyright (C) 2003 Francois Retief + * Steve Kinneberg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CSR1212_H__ +#define __CSR1212_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Compatibility layer */ +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + +#define CSR1212_MALLOC(size) vmalloc((size)) +#define CSR1212_FREE(ptr) vfree(ptr) +#define CSR1212_BE16_TO_CPU(quad) be16_to_cpu(quad) +#define CSR1212_CPU_TO_BE16(quad) cpu_to_be16(quad) +#define CSR1212_BE32_TO_CPU(quad) be32_to_cpu(quad) +#define CSR1212_CPU_TO_BE32(quad) cpu_to_be32(quad) +#define CSR1212_BE64_TO_CPU(quad) be64_to_cpu(quad) +#define CSR1212_CPU_TO_BE64(quad) cpu_to_be64(quad) + +#define CSR1212_LE16_TO_CPU(quad) le16_to_cpu(quad) +#define CSR1212_CPU_TO_LE16(quad) cpu_to_le16(quad) +#define CSR1212_LE32_TO_CPU(quad) le32_to_cpu(quad) +#define CSR1212_CPU_TO_LE32(quad) cpu_to_le32(quad) +#define CSR1212_LE64_TO_CPU(quad) le64_to_cpu(quad) +#define CSR1212_CPU_TO_LE64(quad) cpu_to_le64(quad) + +#include +#define CSR1212_SUCCESS (0) +#define CSR1212_EINVAL (-EINVAL) +#define CSR1212_ENOMEM (-ENOMEM) +#define CSR1212_ENOENT (-ENOENT) +#define CSR1212_EIO (-EIO) +#define CSR1212_EBUSY (-EBUSY) + +#else /* Userspace */ + +#include +#include +#define CSR1212_MALLOC(size) calloc(1,size) +#define CSR1212_FREE(ptr) free(ptr) +#include +#if __BYTE_ORDER == __LITTLE_ENDIAN +#include +#define CSR1212_BE16_TO_CPU(quad) bswap_16(quad) +#define CSR1212_CPU_TO_BE16(quad) bswap_16(quad) +#define CSR1212_BE32_TO_CPU(quad) bswap_32(quad) +#define CSR1212_CPU_TO_BE32(quad) bswap_32(quad) +#define CSR1212_BE64_TO_CPU(quad) bswap_64(quad) +#define CSR1212_CPU_TO_BE64(quad) bswap_64(quad) + +#define CSR1212_LE16_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_LE16(quad) (quad) +#define CSR1212_LE32_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_LE32(quad) (quad) +#define CSR1212_LE64_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_LE64(quad) (quad) +#else +#define CSR1212_BE16_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_BE16(quad) (quad) +#define CSR1212_BE32_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_BE32(quad) (quad) +#define CSR1212_BE64_TO_CPU(quad) (quad) +#define CSR1212_CPU_TO_BE64(quad) (quad) + +#define CSR1212_LE16_TO_CPU(quad) bswap_16(quad) +#define CSR1212_CPU_TO_LE16(quad) bswap_16(quad) +#define CSR1212_LE32_TO_CPU(quad) bswap_32(quad) +#define CSR1212_CPU_TO_LE32(quad) bswap_32(quad) +#define CSR1212_LE64_TO_CPU(quad) bswap_64(quad) +#define CSR1212_CPU_TO_LE64(quad) bswap_64(quad) +#endif + +#include +#define CSR1212_SUCCESS (0) +#define CSR1212_EINVAL (EINVAL) +#define CSR1212_ENOMEM (ENOMEM) +#define CSR1212_ENOENT (ENOENT) +#define CSR1212_EIO (EIO) +#define CSR1212_EBUSY (EBUSY) + +#endif + + +#define CSR1212_KV_VAL_MASK 0xffffff +#define CSR1212_KV_KEY_SHIFT 24 +#define CSR1212_KV_KEY_TYPE_SHIFT 6 +#define CSR1212_KV_KEY_ID_MASK 0x3f +#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* After shift */ + + +/* CSR 1212 key types */ +#define CSR1212_KV_TYPE_IMMEDIATE 0 +#define CSR1212_KV_TYPE_CSR_OFFSET 1 +#define CSR1212_KV_TYPE_LEAF 2 +#define CSR1212_KV_TYPE_DIRECTORY 3 + + +/* CSR 1212 key ids */ +#define CSR1212_KV_ID_DESCRIPTOR 0x01 +#define CSR1212_KV_ID_BUS_DEPENDENT_INFO 0x02 +#define CSR1212_KV_ID_VENDOR 0x03 +#define CSR1212_KV_ID_HARDWARE_VERSION 0x04 +#define CSR1212_KV_ID_MODULE 0x07 +#define CSR1212_KV_ID_NODE_CAPABILITIES 0x0C +#define CSR1212_KV_ID_EUI_64 0x0D +#define CSR1212_KV_ID_UNIT 0x11 +#define CSR1212_KV_ID_SPECIFIER_ID 0x12 +#define CSR1212_KV_ID_VERSION 0x13 +#define CSR1212_KV_ID_DEPENDENT_INFO 0x14 +#define CSR1212_KV_ID_UNIT_LOCATION 0x15 +#define CSR1212_KV_ID_MODEL 0x17 +#define CSR1212_KV_ID_INSTANCE 0x18 +#define CSR1212_KV_ID_KEYWORD 0x19 +#define CSR1212_KV_ID_FEATURE 0x1A +#define CSR1212_KV_ID_EXTENDED_ROM 0x1B +#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID 0x1C +#define CSR1212_KV_ID_EXTENDED_KEY 0x1D +#define CSR1212_KV_ID_EXTENDED_DATA 0x1E +#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR 0x1F +#define CSR1212_KV_ID_DIRECTORY_ID 0x20 +#define CSR1212_KV_ID_REVISION 0x21 + + +/* IEEE 1212 Address space map */ +#define CSR1212_ALL_SPACE_BASE (0x000000000000ULL) +#define CSR1212_ALL_SPACE_SIZE (1ULL << 48) +#define CSR1212_ALL_SPACE_END (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE) + +#define CSR1212_MEMORY_SPACE_BASE (0x000000000000ULL) +#define CSR1212_MEMORY_SPACE_SIZE ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20))) +#define CSR1212_MEMORY_SPACE_END (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE) + +#define CSR1212_PRIVATE_SPACE_BASE (0xffffe0000000ULL) +#define CSR1212_PRIVATE_SPACE_SIZE (256ULL * (1ULL << 20)) +#define CSR1212_PRIVATE_SPACE_END (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE) + +#define CSR1212_REGISTER_SPACE_BASE (0xfffff0000000ULL) +#define CSR1212_REGISTER_SPACE_SIZE (256ULL * (1ULL << 20)) +#define CSR1212_REGISTER_SPACE_END (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE) + +#define CSR1212_CSR_ARCH_REG_SPACE_BASE (0xfffff0000000ULL) +#define CSR1212_CSR_ARCH_REG_SPACE_SIZE (512) +#define CSR1212_CSR_ARCH_REG_SPACE_END (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE) +#define CSR1212_CSR_ARCH_REG_SPACE_OFFSET (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE) + +#define CSR1212_CSR_BUS_DEP_REG_SPACE_BASE (0xfffff0000200ULL) +#define CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE (512) +#define CSR1212_CSR_BUS_DEP_REG_SPACE_END (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE) +#define CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE) + +#define CSR1212_CONFIG_ROM_SPACE_BASE (0xfffff0000400ULL) +#define CSR1212_CONFIG_ROM_SPACE_SIZE (1024) +#define CSR1212_CONFIG_ROM_SPACE_END (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE) +#define CSR1212_CONFIG_ROM_SPACE_OFFSET (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE) + +#define CSR1212_UNITS_SPACE_BASE (0xfffff0000800ULL) +#define CSR1212_UNITS_SPACE_SIZE ((256ULL * (1ULL << 20)) - 2048) +#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE) +#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE) + +#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u_int32_t)) + + +/* Config ROM image structures */ +struct csr1212_bus_info_block_img { + u_int8_t length; + u_int8_t crc_length; + u_int16_t crc; + + /* Must be last */ + u_int32_t data[0]; /* older gcc can't handle [] which is standard */ +}; + +#define CSR1212_KV_KEY(quad) (CSR1212_BE32_TO_CPU(quad) >> CSR1212_KV_KEY_SHIFT) +#define CSR1212_KV_KEY_TYPE(quad) (CSR1212_KV_KEY(quad) >> CSR1212_KV_KEY_TYPE_SHIFT) +#define CSR1212_KV_KEY_ID(quad) (CSR1212_KV_KEY(quad) & CSR1212_KV_KEY_ID_MASK) +#define CSR1212_KV_VAL(quad) (CSR1212_BE32_TO_CPU(quad) & CSR1212_KV_VAL_MASK) + +#define CSR1212_SET_KV_KEY(quad, key) ((quad) = \ + CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | ((key) << CSR1212_KV_KEY_SHIFT))) +#define CSR1212_SET_KV_VAL(quad, val) ((quad) = \ + CSR1212_CPU_TO_BE32((CSR1212_KV_KEY(quad) << CSR1212_KV_KEY_SHIFT) | (val))) +#define CSR1212_SET_KV_TYPEID(quad, type, id) ((quad) = \ + CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | \ + (((((type) & CSR1212_KV_KEY_TYPE_MASK) << CSR1212_KV_KEY_TYPE_SHIFT) | \ + ((id) & CSR1212_KV_KEY_ID_MASK)) << CSR1212_KV_KEY_SHIFT))) + +typedef u_int32_t csr1212_quad_t; + + +struct csr1212_keyval_img { + u_int16_t length; + u_int16_t crc; + + /* Must be last */ + csr1212_quad_t data[0]; /* older gcc can't handle [] which is standard */ +}; + +struct csr1212_leaf { + int len; + u_int32_t *data; +}; + +struct csr1212_dentry { + struct csr1212_dentry *next, *prev; + struct csr1212_keyval *kv; +}; + +struct csr1212_directory { + int len; + struct csr1212_dentry *dentries_head, *dentries_tail; +}; + +struct csr1212_keyval { + struct { + u_int8_t type; + u_int8_t id; + } key; + union { + u_int32_t immediate; + u_int32_t csr_offset; + struct csr1212_leaf leaf; + struct csr1212_directory directory; + } value; + struct csr1212_keyval *associate; + int refcnt; + + /* used in generating and/or parsing CSR image */ + struct csr1212_keyval *next, *prev; /* flat list of CSR elements */ + u_int32_t offset; /* position in CSR from 0xffff f000 0000 */ + u_int8_t valid; /* flag indicating keyval has valid data*/ +}; + + +struct csr1212_cache_region { + struct csr1212_cache_region *next, *prev; + u_int32_t offset_start; /* inclusive */ + u_int32_t offset_end; /* exclusive */ +}; + +struct csr1212_csr_rom_cache { + struct csr1212_csr_rom_cache *next, *prev; + struct csr1212_cache_region *filled_head, *filled_tail; + struct csr1212_keyval *layout_head, *layout_tail; + size_t size; + u_int32_t offset; + struct csr1212_keyval *ext_rom; + size_t len; + + /* Must be last */ + u_int32_t data[0]; /* older gcc can't handle [] which is standard */ +}; + +struct csr1212_csr { + size_t bus_info_len; /* bus info block length in bytes */ + size_t crc_len; /* crc length in bytes */ + u_int32_t *bus_info_data; /* bus info data incl bus name and EUI */ + + void *private_data; /* private_data, bus specific data */ + struct csr1212_bus_ops *ops; + + struct csr1212_keyval *root_kv; + + int max_rom; /* max bytes readable in Config ROM region */ + + /* Items below used for image parsing and generation */ + struct csr1212_csr_rom_cache *cache_head, *cache_tail; +}; + +struct csr1212_bus_ops { + /* This function is used by csr1212 to read additional information + * from remote nodes when parsing a Config ROM (i.e., read Config ROM + * entries located in the Units Space. Must return 0 on success + * anything else indicates an error. */ + int (*bus_read) (struct csr1212_csr *csr, u_int64_t addr, + u_int16_t length, void *buffer, void *private_data); + + /* This function is used by csr1212 to allocate a region in units space + * in the event that Config ROM entries don't all fit in the predefined + * 1K region. The void *private_data parameter is private_data member of struct + * csr1212_csr. */ + u_int64_t (*allocate_addr_range) (u_int64_t size, u_int32_t alignment, + void *private_data); + + + /* This function is used by csr1212 to release a region in units space + * that is no longer needed. */ + void (*release_addr) (u_int64_t addr, void *private_data); + + /* This function is used by csr1212 to determine the max read request + * supported by a remote node when reading the ConfigROM space. Must + * return 0, 1, or 2 per IEEE 1212. */ + int (*get_max_rom) (u_int32_t *bus_info, void *private_data); +}; + + + + +/* Descriptor Leaf manipulation macros */ +#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24 +#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff +#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t)) + +#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) +#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \ + CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK) +#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \ + (&((kv)->value.leaf.data[1])) + +#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \ + ((kv)->value.leaf.data[0] = \ + CSR1212_CPU_TO_BE32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \ + ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT))) +#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \ + ((kv)->value.leaf.data[0] = \ + CSR1212_CPU_TO_BE32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \ + CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \ + ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK))) + +/* Text Descriptor Leaf manipulation macros */ +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28 +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */ +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16 +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */ +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t)) + +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \ + ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \ + (&((kv)->value.leaf.data[2])) + +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \ + ((kv)->value.leaf.data[1] = \ + ((kv)->value.leaf.data[1] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((width) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \ + ((kv)->value.leaf.data[1] = \ + ((kv)->value.leaf.data[1] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((char_set) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT)) +#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \ + ((kv)->value.leaf.data[1] = \ + ((kv)->value.leaf.data[1] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \ + CSR1212_CPU_TO_BE32(((language) & \ + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) + + +/* Icon Descriptor Leaf manipulation macros */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK 0xffffff +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT 30 +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK 0x3 /* after shift */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT 16 +#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK 0xf /* after shift */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff +#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT 16 +#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK 0xffff /* after shift */ +#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK 0xffff +#define CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD (3 * sizeof(u_int32_t)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[2]) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv) \ + ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN(kv) \ + ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) >> \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_SHIFT) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN(kv) \ + (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv) \ + (&((kv)->value.leaf.data[5])) + +static inline u_int32_t *CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(struct csr1212_keyval *kv) +{ + static const int pd[4] = { 0, 4, 16, 256 }; + static const int cs[16] = { 4, 2 }; + int ps = pd[CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv)]; + + return &kv->value.leaf.data[5 + + (ps * cs[CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv)]) / + sizeof(u_int32_t)]; +} + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version) \ + ((kv)->value.leaf.data[2] = \ + ((kv)->value.leaf.data[2] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) | \ + CSR1212_CPU_TO_BE32(((version) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth) \ + ((kv)->value.leaf.data[3] = \ + ((kv)->value.leaf.data[3] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK << \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((palette_depth) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK) << \ + CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space) \ + ((kv)->value.leaf.data[3] = \ + ((kv)->value.leaf.data[3] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK << \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((color_space) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) << \ + CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \ + ((kv)->value.leaf.data[3] = \ + ((kv)->value.leaf.data[3] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \ + CSR1212_CPU_TO_BE32(((language) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan) \ + ((kv)->value.leaf.data[4] = \ + ((kv)->value.leaf.data[4] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK << \ + CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((hscan) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK) << \ + CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT)) + +#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan) \ + ((kv)->value.leaf.data[4] = \ + (((kv)->value.leaf.data[4] & \ + CSR1212_CPU_TO_BE32(~CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) | \ + CSR1212_CPU_TO_BE32(((vscan) & \ + CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) + + +/* Modifiable Descriptor Leaf manipulation macros */ +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT 16 +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK 0xffff +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_SHIFT 32 +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK 0xffff +#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK 0xffffffffULL + +#define CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE(kv) \ + CSR1212_BE16_TO_CPU((kv)->value.leaf.data[0] >> CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE_SHIFT) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_ADDRESS(kv) \ + (CSR1212_BE16_TO_CPU(((u_int64_t)((kv)->value.leaf.data[0])) << \ + CSR1212_MODIFIABLE_DESCRIPTOR_ADDR_HI_SHIFT) | \ + CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1])) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, size) \ + ((kv)->value.leaf.data[0] = \ + ((kv)->value.leaf.data[0] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK << \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))) | \ + CSR1212_CPU_TO_BE32(((size) & \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK) << \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT)) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, addr) \ + ((kv)->value.leaf.data[0] = \ + ((kv)->value.leaf.data[0] & \ + CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) | \ + CSR1212_CPU_TO_BE32(((addr) & \ + CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) + +#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, addr) \ + ((kv)->value.leaf.data[1] = \ + CSR1212_CPU_TO_BE32(addr & CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK)) + + + +/* The following 2 function are for creating new Configuration ROM trees. The + * first function is used for both creating local trees and parsing remote + * trees. The second function adds pertinent information to local Configuration + * ROM trees - namely data for the bus information block. */ +extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, + size_t bus_info_size, + void *private_data); +extern void csr1212_init_local_csr(struct csr1212_csr *csr, + const u_int32_t *bus_info_data, int max_rom); + + +/* The following function destroys a Configuration ROM tree and release all + * memory taken by the tree. */ +extern void csr1212_destroy_csr(struct csr1212_csr *csr); + + +/* The following set of functions are fore creating new keyvals for placement in + * a Configuration ROM tree. Code that creates new keyvals with these functions + * must release those keyvals with csr1212_release_keyval() when they are no + * longer needed. */ +extern struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value); +extern struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, + u_int32_t csr_offset); +extern struct csr1212_keyval *csr1212_new_directory(u_int8_t key); +extern struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, + u_int32_t key, + u_int32_t value); +extern struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, + u_int32_t key, + const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, + u_int32_t specifier_id, + const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth, + u_int16_t cset, + u_int16_t language, + const void *data, + size_t data_len); +extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s); +extern struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version, + u_int8_t palette_depth, + u_int8_t color_space, + u_int16_t language, + u_int16_t hscan, + u_int16_t vscan, + u_int32_t *palette, + u_int32_t *pixels); +extern struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size, + u_int64_t address); +extern struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, + const char *strv[]); + + +/* The following functions manage association between keyvals. Typically, + * Descriptor Leaves and Directories will be associated with another keyval and + * it is desirable for the Descriptor keyval to be place immediately after the + * keyval that it is associated with.*/ +extern int csr1212_associate_keyval(struct csr1212_keyval *kv, + struct csr1212_keyval *associate); +extern void csr1212_disassociate_keyval(struct csr1212_keyval *kv); + + +/* The following functions manage the association of a keyval and directories. + * A keyval may be attached to more than one directory. */ +extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, + struct csr1212_keyval *kv); +extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, + struct csr1212_keyval *kv); + + +/* The following functions create a Configuration ROM image from the tree of + * keyvals provided. csr1212_generate_csr_image() creates a complete image in + * the list of caches available via csr->cache_head. The other functions are + * provided should there be a need to create a flat image without restrictions + * placed by IEEE 1212. */ +extern struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, + struct csr1212_keyval *start_kv, + int start_pos); +extern size_t csr1212_generate_layout_order(struct csr1212_keyval *kv); +extern void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache); +extern int csr1212_generate_csr_image(struct csr1212_csr *csr); + + +/* This is a convience function for reading a block of data out of one of the + * caches in the csr->cache_head list. */ +extern int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, + u_int32_t len); + + +/* The following functions are in place for parsing Configuration ROM images. + * csr1212_parse_keyval() is used should there be a need to directly parse a + * Configuration ROM directly. */ +extern int csr1212_parse_keyval(struct csr1212_keyval *kv, + struct csr1212_csr_rom_cache *cache); +extern int csr1212_parse_csr(struct csr1212_csr *csr); + +/* These are internal functions referenced by inline functions below. */ +extern int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv); +extern void _csr1212_destroy_keyval(struct csr1212_keyval *kv); + + +/* This function allocates a new cache which may be used for either parsing or + * generating sub-sets of Configuration ROM images. */ +static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t offset, + size_t size) +{ + struct csr1212_csr_rom_cache *cache; + + cache = (struct csr1212_csr_rom_cache*)CSR1212_MALLOC(sizeof(struct csr1212_csr_rom_cache) + size); + if (!cache) + return NULL; + + cache->next = NULL; + cache->prev = NULL; + cache->filled_head = NULL; + cache->filled_tail = NULL; + cache->layout_head = NULL; + cache->layout_tail = NULL; + cache->offset = offset; + cache->size = size; + cache->ext_rom = NULL; + + return cache; +} + + +/* This function ensures that a keyval contains data when referencing a keyval + * created by parsing a Configuration ROM. */ +static inline struct csr1212_keyval *csr1212_get_keyval(struct csr1212_csr *csr, + struct csr1212_keyval *kv) +{ + if (!kv) + return NULL; + if (!kv->valid) + if (_csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS) + return NULL; + return kv; +} + + +/* This function increments the reference count for a keyval should there be a + * need for code to retain a keyval that has been parsed. */ +static inline void csr1212_keep_keyval(struct csr1212_keyval *kv) +{ + kv->refcnt++; +} + + +/* This function decrements a keyval's reference count and will destroy the + * keyval when there are no more users of the keyval. This should be called by + * any code that calls csr1212_keep_keyval() or any of the keyval creation + * routines csr1212_new_*(). */ +static inline void csr1212_release_keyval(struct csr1212_keyval *kv) +{ + if (kv->refcnt > 1) + kv->refcnt--; + else + _csr1212_destroy_keyval(kv); +} + + +/* + * This macro allows for looping over the keyval entries in a directory and it + * ensures that keyvals from remote ConfigROMs are parsed properly. + * + * _csr is a struct csr1212_csr * that points to CSR associated with dir. + * _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index). + * _dir is a struct csr1212_keyval * that points to the directory to be looped. + * _pos is a struct csr1212_dentry * that is used internally for indexing. + * + * kv will be NULL upon exit of the loop. + */ +#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \ + for (csr1212_get_keyval((_csr), (_dir)), \ + _pos = (_dir)->value.directory.dentries_head, \ + _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL; \ + (_kv) && (_pos); \ + (_kv->associate == NULL) ? \ + ((_pos = _pos->next), \ + (_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : \ + NULL)) : \ + (_kv = csr1212_get_keyval((_csr), _kv->associate))) + + + +#ifdef __cplusplus + } +#endif + +#endif /* __CSR1212_H__ */ Index: /tags/2.0-rc2/src/libieee1394/cycletimer.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/cycletimer.h (revision 1528) +++ /tags/2.0-rc2/src/libieee1394/cycletimer.h (revision 1528) @@ -0,0 +1,536 @@ +/* + * 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 . + * + */ + +/* Definitions and utility macro's to handle the ISO cycle timer */ + +#ifndef __CYCLETIMER_H__ +#define __CYCLETIMER_H__ + +#include "debugmodule/debugmodule.h" + +#include + +#define CSR_CYCLE_TIME 0x200 +#define CSR_REGISTER_BASE 0xfffff0000000ULL + +#define CYCLES_PER_SECOND 8000U +#define TICKS_PER_CYCLE 3072U +#define TICKS_PER_HALFCYCLE (3072U/2U) +#define TICKS_PER_SECOND 24576000UL +#define TICKS_PER_USEC (24.576000) + +#define USECS_PER_TICK (1.0/TICKS_PER_USEC) +#define USECS_PER_CYCLE (125U) + +#define CYCLE_TIMER_GET_SECS(x) ((((x) & 0xFE000000UL) >> 25)) +#define CYCLE_TIMER_GET_CYCLES(x) ((((x) & 0x01FFF000UL) >> 12)) +#define CYCLE_TIMER_GET_OFFSET(x) ((((x) & 0x00000FFFUL))) + +#define CYCLE_TIMER_SET_SECS(v, x) (((v) & ~0xFE000000UL) | (((x) & 0x7F) << 25)) +#define CYCLE_TIMER_SET_CYCLES(v, x) ((((v) & ~0x01FFF000UL) | (((x) & 0x1FFF) << 12))) +#define CYCLE_TIMER_SET_OFFSET(v, x) ((((v) & ~0x00000FFFUL) | ((x) & 0xFFF))) + + +#define CYCLE_TIMER_TO_TICKS(x) ((CYCLE_TIMER_GET_SECS(x) * TICKS_PER_SECOND) +\ + (CYCLE_TIMER_GET_CYCLES(x) * TICKS_PER_CYCLE ) +\ + (CYCLE_TIMER_GET_OFFSET(x) )) + +// non-efficient versions, to be avoided in critical code +#define TICKS_TO_SECS(x) ((x)/TICKS_PER_SECOND) +#define TICKS_TO_CYCLES(x) (((x)/TICKS_PER_CYCLE) % CYCLES_PER_SECOND) +#define TICKS_TO_OFFSET(x) (((x)%TICKS_PER_CYCLE)) + +#define TICKS_TO_CYCLE_TIMER(x) ( ((TICKS_TO_SECS(x) & 0x7F) << 25) \ + | ((TICKS_TO_CYCLES(x) & 0x1FFF) << 12) \ + | ((TICKS_TO_OFFSET(x) & 0xFFF))) + +#define TICKS_TO_SYT(x) (((TICKS_TO_CYCLES(x) & 0xF) << 12) \ + | ((TICKS_TO_OFFSET(x) & 0xFFF))) + +#define CYCLE_TIMER_UNWRAP_TICKS(x) (((uint64_t)(x)) \ + + (127ULL * TICKS_PER_SECOND) \ + + (CYCLES_PER_SECOND * TICKS_PER_CYCLE) \ + + (TICKS_PER_CYCLE) \ + ) +#define CYCLE_TIMER_WRAP_TICKS(x) ((x % TICKS_PER_SECOND)) + +#define INVALID_TIMESTAMP_TICKS 0xFFFFFFFFFFFFFFFFULL + +DECLARE_GLOBAL_DEBUG_MODULE; + +/** + * @brief Wraps x to the maximum number of ticks + * + * The input value is wrapped to the maximum value of the cycle + * timer, in ticks (128sec * 24576000 ticks/sec). + * + * @param x time to wrap + * @return wrapped time + */ +static inline uint64_t wrapAtMaxTicks(uint64_t x) { + if (x >= TICKS_PER_SECOND * 128L) { + x -= TICKS_PER_SECOND * 128L; + } + +#ifdef DEBUG + if (x >= TICKS_PER_SECOND * 128L) { + debugWarning("insufficient wrapping: %llu\n",x); + } +#endif + + return x; +} + +/** + * @brief Wraps x to the minimum number of ticks + * + * The input value is wrapped to the minimum value of the cycle + * timer, in ticks (= 0). + * + * @param x time to wrap + * @return wrapped time + */ +static inline int64_t wrapAtMinTicks(int64_t x) { + if (x < 0) { + x += TICKS_PER_SECOND * 128L; + } + +#ifdef DEBUG + if (x < 0) { + debugWarning("insufficient wrapping: %lld\n",x); + } +#endif + + return (int64_t)x; +} + +/** + * @brief Wraps both at minimum and maximum value for ticks + * + * The input value is wrapped to the maximum value of the cycle + * timer, in ticks (128sec * 24576000 ticks/sec), and + * to the minimum value of the cycle timer, in ticks (= 0). + * + * @param x value to wrap + * @return wrapped value + */ +static inline int64_t wrapAtMinMaxTicks(int64_t x) { + + if (x < 0) { + x += TICKS_PER_SECOND * 128L; + } else if (x >= (int64_t)(TICKS_PER_SECOND * 128L)) { + x -= TICKS_PER_SECOND * 128L; + } + +#ifdef DEBUG + if (x >= (int64_t)(TICKS_PER_SECOND * 128L)) { + debugWarning("insufficient wrapping (max): %llu\n",x); + } + if (x < 0) { + debugWarning("insufficient wrapping (min): %lld\n",x); + } +#endif + return x; + +} + +/** + * @brief Computes the sum of two cycle values + * + * This function computes a sum between cycles + * such that it respects wrapping (at 8000 cycles). + * + * The passed arguments are assumed to be valid cycle numbers, + * i.e. they should be wrapped at 8000 cycles + * + * See addTicks + * + * @param x First cycle value + * @param y Second cycle value + * @return the sum x+y, wrapped + */ +static inline unsigned int addCycles(unsigned int x, unsigned int y) { + unsigned int sum = x + y; +#ifdef DEBUG + if (x >= CYCLES_PER_SECOND || y >= CYCLES_PER_SECOND ) { + debugWarning("At least one argument not wrapped correctly: x=%u, y=%u\n",x,y); + } +#endif + + // since both x and y are < CYCLES_PER_SECOND this should be enough to unwrap + if (sum > CYCLES_PER_SECOND) sum -= CYCLES_PER_SECOND; + return sum; +} + +/** + * @brief Computes a difference between cycles + * + * This function computes a difference between cycles + * such that it respects wrapping (at 8000 cycles). + * + * See diffTicks + * + * @param x First cycle value + * @param y Second cycle value + * @return the difference x-y, unwrapped + */ +static inline int diffCycles(unsigned int x, unsigned int y) { + int diff = (int)x - (int)y; + + // the maximal difference we allow (4000 cycles) + const int max=CYCLES_PER_SECOND/2; + + if(diff > max) { + diff -= CYCLES_PER_SECOND; + } else if (diff < -max) { + diff += CYCLES_PER_SECOND; + } + + return diff; +} + +/** + * @brief Computes a difference between timestamps + * + * This function computes a difference between timestamps + * such that it respects wrapping. + * + * If x wraps around, but y doesn't, the result of x-y is + * negative and very large. However the real difference is + * not large. It can be calculated by unwrapping x and then + * calculating x-y. + * + * @param x First timestamp + * @param y Second timestamp + * @return the difference x-y, unwrapped + */ +static inline int64_t diffTicks(int64_t x, int64_t y) { + int64_t diff=(int64_t)x - (int64_t)y; + + // the maximal difference we allow (64secs) + const int64_t wrapvalue=((int64_t)TICKS_PER_SECOND)*128LL; + const int64_t max=wrapvalue/2LL; + + if(diff > max) { + // this means that y has wrapped, but + // x has not. we should unwrap y + // by adding TICKS_PER_SECOND*128L, meaning that we should substract + // this value from diff + diff -= wrapvalue; + } else if (diff < -max) { + // this means that x has wrapped, but + // y has not. we should unwrap x + // by adding TICKS_PER_SECOND*128L, meaning that we should add + // this value to diff + diff += wrapvalue; + } + +#ifdef DEBUG + if(diff > max || diff < -max) { + debugWarning("difference does not make any sense\n"); + debugWarning("diff=%lld max=%lld\n", diff, max); + + } +#endif + + return (int64_t)diff; + +} + +/** + * @brief Computes a sum of timestamps + * + * This function computes a sum of timestamps in ticks, + * wrapping the result if necessary. + * + * @param x First timestamp + * @param y Second timestamp + * @return the sum x+y, wrapped + */ +static inline uint64_t addTicks(uint64_t x, uint64_t y) { + uint64_t sum=x+y; + + return wrapAtMaxTicks(sum); +} + +/** + * @brief Computes a substraction of timestamps + * + * This function computes a substraction of timestamps in ticks, + * wrapping the result if necessary. + * + * @param x First timestamp + * @param y Second timestamp + * @return the difference x-y, wrapped + */ +static inline uint64_t substractTicks(uint64_t x, uint64_t y) { + int64_t subs=x-y; + + return wrapAtMinTicks(subs); +} + +/** + * @brief Converts a received SYT timestamp to a full timestamp in ticks. + * + * + * @param syt_timestamp The SYT timestamp as present in the packet + * @param rcv_cycle The cycle this timestamp was received on + * @param ctr_now The current value of the cycle timer ('now') + * @return + */ +static inline uint64_t sytRecvToFullTicks(uint64_t syt_timestamp, unsigned int rcv_cycle, uint64_t ctr_now) { + uint64_t timestamp; + + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%04llX CY=%u CTR=%08llX\n", + syt_timestamp, rcv_cycle, ctr_now); + + // reconstruct the full cycle + uint64_t cc_cycles=CYCLE_TIMER_GET_CYCLES(ctr_now); + uint64_t cc_seconds=CYCLE_TIMER_GET_SECS(ctr_now); + + // check for bogus ctr + // the cycle timer should be ahead of the receive timer + int diff_cycles = diffCycles(cc_cycles, rcv_cycle); + if (diff_cycles<0) { + debugWarning("current cycle timer not ahead of receive cycle: rcv: %u / cc: %llu (%d)\n", + rcv_cycle, cc_cycles, diff_cycles); + } + + // the cycletimer has wrapped since this packet was received + // we want cc_seconds to reflect the 'seconds' at the point this + // was received + if (rcv_cycle>cc_cycles && (diff_cycles>=0)) { + if (cc_seconds) { + cc_seconds--; + } else { + // seconds has wrapped around, so we'd better not substract 1 + // the good value is 127 + cc_seconds=127; + } + } + + // reconstruct the top part of the timestamp using the current cycle number + uint64_t rcv_cycle_masked=rcv_cycle & 0xF; + uint64_t syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp); + + // if this is true, wraparound has occurred, undo this wraparound + if(syt_cycle= 8000) { + debugWarning("insufficient unwrapping\n"); + } +#endif + timestamp = new_cycles * TICKS_PER_CYCLE; + // add one second due to wraparound + timestamp += TICKS_PER_SECOND; + } + + timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); + + timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND); + + #ifdef DEBUG + if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) { + debugWarning("back-converted timestamp not equal to SYT\n"); + debugWarning("TS=%011llu TSC=%08lX SYT=%04X\n", + timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp); + } + #endif + + return timestamp; +} + +/** + * @brief Converts a received SYT timestamp to a full timestamp in ticks. + * + * + * @param syt_timestamp The SYT timestamp as present in the packet + * @param rcv_ctr The CTR value this timestamp was received on (offset can be 0) + * @return + */ +static inline uint64_t sytRecvToFullTicks2(uint64_t syt_timestamp, uint32_t rcv_ctr) { + uint64_t timestamp; + + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%04llX RCV_CTR=%08X\n", + syt_timestamp, rcv_ctr); + + // reconstruct the top part of the timestamp using the current cycle number + unsigned int rcv_cycle = CYCLE_TIMER_GET_CYCLES(rcv_ctr); + unsigned int rcv_cycle_masked = rcv_cycle & 0xF; + unsigned int syt_cycle = CYCLE_TIMER_GET_CYCLES(syt_timestamp); + + // if this is true, wraparound has occurred, undo this wraparound + if(syt_cycle= 8000) { + debugWarning("insufficient unwrapping\n"); + } +#endif + timestamp = rcv_cycle * TICKS_PER_CYCLE; + // add one second due to wraparound + timestamp += TICKS_PER_SECOND; + } + + timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); + + timestamp = addTicks(timestamp, CYCLE_TIMER_GET_SECS(rcv_ctr) * TICKS_PER_SECOND); + + #ifdef DEBUG + if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) { + debugWarning("back-converted timestamp not equal to SYT\n"); + debugWarning("TS=%011llu TSC=%08lX SYT=%04X\n", + timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp); + } + #endif + + return timestamp; +} + +/** + * @brief Converts a transmit SYT timestamp to a full timestamp in ticks. + * + * The difference between sytRecvToFullTicks and sytXmitToFullTicks is + * the way SYT cycle wraparound is detected: in the receive version, + * wraparound is present if rcv_cycle > current_cycle. In the xmit + * version this is when current_cycle > xmt_cycle. + * + * @param syt_timestamp The SYT timestamp as present in the packet + * @param xmt_cycle The cycle this timestamp was received on + * @param ctr_now The current value of the cycle timer ('now') + * @return + */ +static inline uint64_t sytXmitToFullTicks(uint64_t syt_timestamp, unsigned int xmt_cycle, uint64_t ctr_now) { + uint64_t timestamp; + + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "SYT=%08llX CY=%04X CTR=%08llX\n", + syt_timestamp, xmt_cycle, ctr_now); + + // reconstruct the full cycle + uint64_t cc_cycles=CYCLE_TIMER_GET_CYCLES(ctr_now); + uint64_t cc_seconds=CYCLE_TIMER_GET_SECS(ctr_now); + + // check for bogus CTR + int diff_cycles = diffCycles(xmt_cycle, cc_cycles); + if (diff_cycles<0) { + debugWarning("xmit cycle not ahead of current cycle: xmt: %u / cc: %llu (%d)\n", + xmt_cycle, cc_cycles, diff_cycles); + } + + // the cycletimer has wrapped since this packet was received + // we want cc_seconds to reflect the 'seconds' at the point this + // is to be transmitted + if (cc_cycles>xmt_cycle && (diff_cycles>=0)) { + if (cc_seconds) { + cc_seconds--; + } else { + // seconds has wrapped around, so we'd better not substract 1 + // the good value is 127 + cc_seconds=127; + } + } + + // reconstruct the top part of the timestamp using the current cycle number + uint64_t xmt_cycle_masked=xmt_cycle & 0xF; + uint64_t syt_cycle=CYCLE_TIMER_GET_CYCLES(syt_timestamp); + + // if this is true, wraparound has occurred, undo this wraparound + if(syt_cycle= 8000) { + debugWarning("insufficient unwrapping\n"); + } +#endif + timestamp = new_cycles * TICKS_PER_CYCLE; + // add one second due to wraparound + timestamp += TICKS_PER_SECOND; + } + + timestamp += CYCLE_TIMER_GET_OFFSET(syt_timestamp); + + timestamp = addTicks(timestamp, cc_seconds * TICKS_PER_SECOND); + + #ifdef DEBUG + if(( TICKS_TO_CYCLE_TIMER(timestamp) & 0xFFFF) != syt_timestamp) { + debugWarning("back-converted timestamp not equal to SYT\n"); + debugWarning("TS=%011llu TSC=%08lX SYT=%04X\n", + timestamp, TICKS_TO_CYCLE_TIMER(timestamp), syt_timestamp); + } + #endif + + return timestamp; +} + +#endif // __CYCLETIMER_H__ Index: /tags/2.0-rc2/src/libieee1394/CycleTimerHelper.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/CycleTimerHelper.h (revision 1525) +++ /tags/2.0-rc2/src/libieee1394/CycleTimerHelper.h (revision 1525) @@ -0,0 +1,182 @@ +/* + * 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 . + * + */ +#ifndef __CYCLETIMERHELPER_H__ +#define __CYCLETIMERHELPER_H__ + +/** + * Implements a DLL based mechanism to track the cycle timer + * register of the Ieee1394Service pointed to by the 'parent'. + * + * A DLL mechanism is performance-wise better suited, since it + * does not require an OS call. Hence we run a thread to update + * the DLL at regular time intervals, and then use the DLL to + * generate a cycle timer estimate for the parent to pass on + * to it's clients. + * + * The idea is to make reading the cycle timer real-time safe, + * which isn't (necessarily)the case for the direct raw1394 call, + * since it's a kernel call that could block (although the current + * implementation is RT safe). + * + * This also allows us to run on systems not having the + * raw1394_read_cycle_timer kernel call. We can always do a normal + * read of our own cycle timer register, but that's not very accurate. + * The accuracy is improved by this DLL mechanism. Still not as good + * as when using the raw1394_read_cycle_timer call, but anyway. + * + * On the long run this code will also allow us to map system time + * on to 1394 time for the current host controller, hence enabling + * different clock domains to operate together. + */ + +#include "libutil/Thread.h" +#include "libutil/SystemTimeSource.h" +#include "cycletimer.h" + +#include "libutil/Functors.h" +#include "libutil/Mutex.h" + +#include "debugmodule/debugmodule.h" + +class Ieee1394Service; + +class CycleTimerHelper : public Util::RunnableInterface +{ +public: + CycleTimerHelper(Ieee1394Service &, unsigned int); + CycleTimerHelper(Ieee1394Service &, unsigned int, bool rt, int prio); + ~CycleTimerHelper(); + + virtual bool Init(); + virtual bool Execute(); + + bool setThreadParameters(bool rt, int priority); + bool Start(); + + /** + * @brief get the current cycle timer value (in ticks) + * @note thread safe + */ + uint32_t getCycleTimerTicks(); + + /** + * @brief get the cycle timer value for a specific time instant (in ticks) + * @note thread safe + */ + uint32_t getCycleTimerTicks(uint64_t now); + + /** + * @brief get the current cycle timer value (in CTR format) + * @note thread safe + */ + uint32_t getCycleTimer(); + + /** + * @brief get the cycle timer value for a specific time instant (in CTR format) + * @note thread safe + */ + uint32_t getCycleTimer(uint64_t now); + + /** + * @brief get the system time for a specific cycle timer value (in ticks) + * @note thread safe + */ + uint64_t getSystemTimeForCycleTimerTicks(uint32_t ticks); + + /** + * @brief get the system time for a specific cycle timer value (in CTR format) + * @note thread safe + */ + uint64_t getSystemTimeForCycleTimer(uint32_t ctr); + + float getRate(); + float getNominalRate(); + + /** + * @brief handle a bus reset + */ + void busresetHandler(); + + void setVerboseLevel(int l); + +private: + bool readCycleTimerWithRetry(uint32_t *cycle_timer, uint64_t *local_time, int ntries); + bool initValues(); + +#if IEEE1394SERVICE_USE_CYCLETIMER_DLL + bool initDLL(); +#endif + + Ieee1394Service &m_Parent; + // parameters + uint32_t m_ticks_per_update; + uint32_t m_usecs_per_update; + + float m_avg_wakeup_delay; + + // state variables + double m_dll_e2; + + double m_current_time_usecs; + double m_next_time_usecs; + double m_current_time_ticks; + double m_next_time_ticks; + bool m_first_run; + ffado_microsecs_t m_sleep_until; + + uint32_t m_cycle_timer_prev; + uint64_t m_cycle_timer_ticks_prev; + + double m_dll_coeff_b; + double m_dll_coeff_c; + + // cached vars used for computation + struct compute_vars { + uint64_t usecs; + uint64_t ticks; + double rate; + }; + + #define CTRHELPER_NB_SHADOW_VARS 8 + struct compute_vars m_shadow_vars[CTRHELPER_NB_SHADOW_VARS]; + volatile unsigned int m_current_shadow_idx; + + // Threading + Util::Thread * m_Thread; + bool m_realtime; + unsigned int m_priority; + Util::Mutex* m_update_lock; + + // busreset handling + Util::Functor* m_busreset_functor; + bool m_unhandled_busreset; + +#ifdef DEBUG + uint64_t m_last_loop_entry; + int m_successive_short_loops; +#endif + + // debug stuff + DECLARE_DEBUG_MODULE; +}; +#endif Index: /tags/2.0-rc2/src/libieee1394/ieee1394service.cpp =================================================================== --- /tags/2.0-rc2/src/libieee1394/ieee1394service.cpp (revision 1451) +++ /tags/2.0-rc2/src/libieee1394/ieee1394service.cpp (revision 1451) @@ -0,0 +1,1392 @@ +/* + * 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 . + * + */ + +#include "config.h" +#include "ieee1394service.h" +#include "cycletimer.h" +#include "IsoHandlerManager.h" +#include "CycleTimerHelper.h" + +#include +#include + +#include "libutil/SystemTimeSource.h" +#include "libutil/Watchdog.h" +#include "libutil/PosixMutex.h" +#include "libutil/Configuration.h" + +#include +#include "libutil/ByteSwap.h" + +#include + +#include +#include + +using namespace std; + +IMPL_DEBUG_MODULE( Ieee1394Service, Ieee1394Service, DEBUG_LEVEL_NORMAL ); + +Ieee1394Service::Ieee1394Service() + : m_configuration( NULL ) + , m_handle( 0 ) + , m_handle_lock( new Util::PosixMutex("SRCVHND") ) + , m_resetHandle( 0 ) + , m_util_handle( 0 ) + , m_port( -1 ) + , m_RHThread_lock( new Util::PosixMutex("SRVCRH") ) + , m_threadRunning( false ) + , m_realtime ( false ) + , m_base_priority ( 0 ) + , m_pIsoManager( new IsoHandlerManager( *this ) ) + , m_pCTRHelper ( new CycleTimerHelper( *this, IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC ) ) + , m_have_new_ctr_read ( false ) + , m_filterFCPResponse ( false ) + , m_pWatchdog ( new Util::Watchdog() ) +{ + for (unsigned int i=0; i<64; i++) { + m_channels[i].channel=-1; + m_channels[i].bandwidth=-1; + m_channels[i].alloctype=AllocFree; + m_channels[i].xmit_node=0xFFFF; + m_channels[i].xmit_plug=-1; + m_channels[i].recv_node=0xFFFF; + m_channels[i].recv_plug=-1; + } +} + +Ieee1394Service::Ieee1394Service(bool rt, int prio) + : m_configuration( NULL ) + , m_handle( 0 ) + , m_handle_lock( new Util::PosixMutex("SRCVHND") ) + , m_resetHandle( 0 ) + , m_util_handle( 0 ) + , m_port( -1 ) + , m_RHThread_lock( new Util::PosixMutex("SRVCRH") ) + , m_threadRunning( false ) + , m_realtime ( rt ) + , m_base_priority ( prio ) + , m_pIsoManager( new IsoHandlerManager( *this, rt, prio ) ) + , m_pCTRHelper ( new CycleTimerHelper( *this, IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC, + rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME, + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO ) ) + , m_have_new_ctr_read ( false ) + , m_filterFCPResponse ( false ) + , m_pWatchdog ( new Util::Watchdog() ) +{ + for (unsigned int i=0; i<64; i++) { + m_channels[i].channel=-1; + m_channels[i].bandwidth=-1; + m_channels[i].alloctype=AllocFree; + m_channels[i].xmit_node=0xFFFF; + m_channels[i].xmit_plug=-1; + m_channels[i].recv_node=0xFFFF; + m_channels[i].recv_plug=-1; + } +} + +Ieee1394Service::~Ieee1394Service() +{ + delete m_pIsoManager; + delete m_pCTRHelper; + stopRHThread(); + + delete m_pWatchdog; + if ( m_handle ) { + raw1394_destroy_handle( m_handle ); + } + delete m_handle_lock; + + if ( m_resetHandle ) { + raw1394_destroy_handle( m_resetHandle ); + } + delete m_RHThread_lock; + if ( m_util_handle ) { + raw1394_destroy_handle( m_util_handle ); + } +} + +bool +Ieee1394Service::useConfiguration(Util::Configuration *c) +{ + m_configuration = c; + return configurationUpdated(); +} + +bool +Ieee1394Service::configurationUpdated() +{ + if(m_configuration) { + + } + return true; +} + +#define DEVICEFAILTEXT "Could not get libraw1394 handle.\n\ +This usually means:\n\ + a) The device-node /dev/raw1394 doesn't exists because you don't have a\n\ + (recognized) firewire controller.\n \ + b) The modules needed aren't loaded. This is not in the scope of ffado but of\n\ + your distribution, so if you have a firewire controller that should be\n\ + supported and the modules aren't loaded, file a bug with your distributions\n\ + bug tracker.\n \ + c) You don't have permissions to access /dev/raw1394. 'ls -l /dev/raw1394'\n\ + shows the device-node with its permissions, make sure you belong to the\n\ + right group and the group is allowed to access the device.\n" + +int +Ieee1394Service::detectNbPorts() +{ + raw1394handle_t tmp_handle = raw1394_new_handle(); + if ( tmp_handle == NULL ) { + debugError(DEVICEFAILTEXT); + return -1; + } + struct raw1394_portinfo pinf[IEEE1394SERVICE_MAX_FIREWIRE_PORTS]; + int nb_detected_ports = raw1394_get_port_info(tmp_handle, pinf, IEEE1394SERVICE_MAX_FIREWIRE_PORTS); + raw1394_destroy_handle(tmp_handle); + + if (nb_detected_ports < 0) { + debugError("Failed to detect number of ports\n"); + return -1; + } + return nb_detected_ports; +} + +void +Ieee1394Service::doBusReset() { + debugOutput(DEBUG_LEVEL_VERBOSE, "Issue bus reset on service %p (port %d).\n", this, getPort()); + raw1394_reset_bus(m_handle); +} + +/** + * This function waits until there are no bus resets generated in a sleep_time_ms interval + * @param nb_tries number of tries to take + * @param sleep_time_ms sleep between tries + * @return true if the storm passed + */ +bool +Ieee1394Service::waitForBusResetStormToEnd( int nb_tries, int sleep_time_ms ) { + unsigned int gen_current; + do { + gen_current = getGeneration(); + debugOutput(DEBUG_LEVEL_VERBOSE, "Waiting... (gen: %u)\n", gen_current); + + // wait for a while + Util::SystemTimeSource::SleepUsecRelative( sleep_time_ms * 1000); + } while (gen_current != getGeneration() && --nb_tries); + + debugOutput(DEBUG_LEVEL_VERBOSE, "Bus reset storm over at gen: %u\n", gen_current); + + if (!nb_tries) { + debugError( "Bus reset storm did not stop on time...\n"); + return false; + } + return true; +} + +bool +Ieee1394Service::initialize( int port ) +{ + using namespace std; + + int nb_ports = detectNbPorts(); + if (port + 1 > nb_ports) { + debugFatal("Requested port (%d) out of range (# ports: %d)\n", port, nb_ports); + } + + if(!m_pWatchdog) { + debugError("No valid RT watchdog found.\n"); + return false; + } + if(!m_pWatchdog->start()) { + debugError("Could not start RT watchdog.\n"); + return false; + } + + m_handle = raw1394_new_handle_on_port( port ); + if ( !m_handle ) { + if ( !errno ) { + debugFatal("libraw1394 not compatible\n"); + } else { + debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s\n", + strerror(errno) ); + debugFatal("Is ieee1394 and raw1394 driver loaded?\n"); + } + return false; + } + + m_resetHandle = raw1394_new_handle_on_port( port ); + if ( !m_resetHandle ) { + if ( !errno ) { + debugFatal("libraw1394 not compatible\n"); + } else { + debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s", + strerror(errno) ); + debugFatal("Is ieee1394 and raw1394 driver loaded?\n"); + } + return false; + } + + m_util_handle = raw1394_new_handle_on_port( port ); + if ( !m_util_handle ) { + if ( !errno ) { + debugFatal("libraw1394 not compatible\n"); + } else { + debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s", + strerror(errno) ); + debugFatal("Is ieee1394 and raw1394 driver loaded?\n"); + } + return false; + } + + // test the cycle timer read function + int err; + uint32_t cycle_timer; + uint64_t local_time; + err=raw1394_read_cycle_timer(m_handle, &cycle_timer, &local_time); + if(err) { + debugOutput(DEBUG_LEVEL_VERBOSE, "raw1394_read_cycle_timer failed.\n"); + debugOutput(DEBUG_LEVEL_VERBOSE, " Error descr: %s\n", strerror(err)); + debugWarning("==================================================================\n"); + debugWarning(" This system doesn't support the raw1394_read_cycle_timer call. \n"); + debugWarning(" Fallback to indirect CTR read method. \n"); + debugWarning(" FFADO should work, but achieving low-latency might be a problem. \n"); + debugWarning(" Upgrade the kernel to version 2.6.21 or higher to solve this. \n"); + debugWarning("==================================================================\n"); + m_have_new_ctr_read = false; + } else { + debugOutput(DEBUG_LEVEL_VERBOSE, "This system supports the raw1394_read_cycle_timer call, using it.\n"); + m_have_new_ctr_read = true; + } + + m_port = port; + + // obtain port name + raw1394handle_t tmp_handle = raw1394_new_handle(); + if ( tmp_handle == NULL ) { + debugError("Could not get temporary libraw1394 handle.\n"); + return false; + } + struct raw1394_portinfo pinf[IEEE1394SERVICE_MAX_FIREWIRE_PORTS]; + int nb_detected_ports = raw1394_get_port_info(tmp_handle, pinf, IEEE1394SERVICE_MAX_FIREWIRE_PORTS); + raw1394_destroy_handle(tmp_handle); + + if (nb_detected_ports < 0) { + debugError("Failed to detect number of ports\n"); + return false; + } + + if(nb_detected_ports && port < IEEE1394SERVICE_MAX_FIREWIRE_PORTS) { + m_portName = pinf[port].name; + } else { + m_portName = "Unknown"; + } + if (m_portName == "") { + m_portName = "Unknown"; + } + + // set userdata + raw1394_set_userdata( m_handle, this ); + raw1394_set_userdata( m_resetHandle, this ); + raw1394_set_userdata( m_util_handle, this ); + raw1394_set_bus_reset_handler( m_resetHandle, + this->resetHandlerLowLevel ); + + int split_timeout = IEEE1394SERVICE_MIN_SPLIT_TIMEOUT_USECS; + if(m_configuration) { + m_configuration->getValueForSetting("ieee1394.min_split_timeout_usecs", split_timeout); + } + + // set SPLIT_TIMEOUT to one second to cope with DM1x00 devices that + // send responses regardless of the timeout + int timeout = getSplitTimeoutUsecs(getLocalNodeId()); + debugOutput(DEBUG_LEVEL_VERBOSE, "Minimum SPLIT_TIMEOUT: %d. Current: %d\n", split_timeout, timeout); + if (timeout < split_timeout) { + if(!setSplitTimeoutUsecs(getLocalNodeId(), split_timeout+124)) { + debugWarning("Could not set SPLIT_TIMEOUT to min requested (%d)\n", split_timeout); + } + timeout = getSplitTimeoutUsecs(getLocalNodeId()); + if (timeout < split_timeout) { + debugWarning("Set SPLIT_TIMEOUT to min requested (%d) did not succeed\n", split_timeout); + } + } + + // init helpers + if(!m_pCTRHelper) { + debugFatal("No CycleTimerHelper available, bad!\n"); + return false; + } + m_pCTRHelper->setVerboseLevel(getDebugLevel()); + if(!m_pCTRHelper->Start()) { + debugFatal("Could not start CycleTimerHelper\n"); + return false; + } + + if(!m_pIsoManager) { + debugFatal("No IsoHandlerManager available, bad!\n"); + return false; + } + m_pIsoManager->setVerboseLevel(getDebugLevel()); + + if(!m_pIsoManager->init()) { + debugFatal("Could not initialize IsoHandlerManager\n"); + return false; + } + + startRHThread(); + + // make sure that the thread parameters of all our helper threads are OK + if(!setThreadParameters(m_realtime, m_base_priority)) { + debugFatal("Could not set thread parameters\n"); + return false; + } + return true; +} + +bool +Ieee1394Service::setThreadParameters(bool rt, int priority) { + bool result = true; + if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; + if (priority < THREAD_MIN_RTPRIO) priority = THREAD_MIN_RTPRIO; + m_base_priority = priority; + m_realtime = rt; + if (m_pIsoManager) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Switching IsoManager to (rt=%d, prio=%d)\n", + rt, priority); + result &= m_pIsoManager->setThreadParameters(rt, priority); + } + if (m_pCTRHelper) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Switching CycleTimerHelper to (rt=%d, prio=%d)\n", + rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME, + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO); + result &= m_pCTRHelper->setThreadParameters(rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME, + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO); + } + return result; +} + +int +Ieee1394Service::getNodeCount() +{ + Util::MutexLockHelper lock(*m_handle_lock); + return raw1394_get_nodecount( m_handle ); +} + +nodeid_t Ieee1394Service::getLocalNodeId() { + Util::MutexLockHelper lock(*m_handle_lock); + return raw1394_get_local_id(m_handle) & 0x3F; +} + +/** + * Returns the current value of the cycle timer (in ticks) + * + * @return the current value of the cycle timer (in ticks) + */ + +uint32_t +Ieee1394Service::getCycleTimerTicks() { + return m_pCTRHelper->getCycleTimerTicks(); +} + +/** + * Returns the current value of the cycle timer (as is) + * + * @return the current value of the cycle timer (as is) + */ +uint32_t +Ieee1394Service::getCycleTimer() { + return m_pCTRHelper->getCycleTimer(); +} + +/** + * Returns the current value of the cycle timer (in ticks) + * for a specific time instant (usecs since epoch) + * @return the current value of the cycle timer (in ticks) + */ + +uint32_t +Ieee1394Service::getCycleTimerTicks(uint64_t t) { + return m_pCTRHelper->getCycleTimerTicks(t); +} + +/** + * Returns the current value of the cycle timer (as is) + * for a specific time instant (usecs since epoch) + * @return the current value of the cycle timer (as is) + */ +uint32_t +Ieee1394Service::getCycleTimer(uint64_t t) { + return m_pCTRHelper->getCycleTimer(t); +} + +uint64_t +Ieee1394Service::getSystemTimeForCycleTimerTicks(uint32_t ticks) { + return m_pCTRHelper->getSystemTimeForCycleTimerTicks(ticks); +} + +uint64_t +Ieee1394Service::getSystemTimeForCycleTimer(uint32_t ctr) { + return m_pCTRHelper->getSystemTimeForCycleTimer(ctr); +} + +bool +Ieee1394Service::readCycleTimerReg(uint32_t *cycle_timer, uint64_t *local_time) +{ + if(m_have_new_ctr_read) { + int err; + err = raw1394_read_cycle_timer(m_util_handle, cycle_timer, local_time); + if(err) { + debugWarning("raw1394_read_cycle_timer: %s\n", strerror(err)); + return false; + } + return true; + } else { + // do a normal read of the CTR register + // the disadvantage is that local_time and cycle time are not + // read at the same time instant (scheduling issues) + *local_time = getCurrentTimeAsUsecs(); + if ( raw1394_read( m_util_handle, + getLocalNodeId() | 0xFFC0, + CSR_REGISTER_BASE | CSR_CYCLE_TIME, + sizeof(uint32_t), cycle_timer ) == 0 ) { + *cycle_timer = CondSwapFromBus32(*cycle_timer); + return true; + } else { + return false; + } + } +} + +uint64_t +Ieee1394Service::getCurrentTimeAsUsecs() { + return Util::SystemTimeSource::getCurrentTimeAsUsecs(); +} + +bool +Ieee1394Service::read( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* buffer ) +{ + Util::MutexLockHelper lock(*m_handle_lock); + return readNoLock(nodeId, addr, length, buffer); +} + +bool +Ieee1394Service::readNoLock( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* buffer ) +{ + if (nodeId == INVALID_NODE_ID) { + debugWarning("operation on invalid node\n"); + return false; + } + if ( raw1394_read( m_handle, nodeId, addr, length*4, buffer ) == 0 ) { + + #ifdef DEBUG + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, + "read: node 0x%hX, addr = 0x%016llX, length = %u\n", + nodeId, addr, length); + printBuffer( DEBUG_LEVEL_VERY_VERBOSE, length, buffer ); + #endif + + return true; + } else { + #ifdef DEBUG + debugOutput(DEBUG_LEVEL_NORMAL, + "raw1394_read failed: node 0x%hX, addr = 0x%016llX, length = %u\n", + nodeId, addr, length); + #endif + return false; + } +} + +bool +Ieee1394Service::read_quadlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_quadlet_t* buffer ) +{ + return read( nodeId, addr, sizeof( *buffer )/4, buffer ); +} + +bool +Ieee1394Service::read_octlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_octlet_t* buffer ) +{ + return read( nodeId, addr, sizeof( *buffer )/4, + reinterpret_cast( buffer ) ); +} + +bool +Ieee1394Service::write( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* data ) +{ + Util::MutexLockHelper lock(*m_handle_lock); + return writeNoLock(nodeId, addr, length, data); +} + +bool +Ieee1394Service::writeNoLock( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* data ) +{ + if (nodeId == INVALID_NODE_ID) { + debugWarning("operation on invalid node\n"); + return false; + } + + #ifdef DEBUG + debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"write: node 0x%hX, addr = 0x%016llX, length = %d\n", + nodeId, addr, length); + printBuffer( DEBUG_LEVEL_VERY_VERBOSE, length, data ); + #endif + + return raw1394_write( m_handle, nodeId, addr, length*4, data ) == 0; +} + +bool +Ieee1394Service::write_quadlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_quadlet_t data ) +{ + return write( nodeId, addr, sizeof( data )/4, &data ); +} + +bool +Ieee1394Service::write_octlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_octlet_t data ) +{ + return write( nodeId, addr, sizeof( data )/4, + reinterpret_cast( &data ) ); +} + +bool +Ieee1394Service::lockCompareSwap64( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_octlet_t compare_value, + fb_octlet_t swap_value, + fb_octlet_t* result ) +{ + if (nodeId == INVALID_NODE_ID) { + debugWarning("operation on invalid node\n"); + return false; + } + #ifdef DEBUG + debugOutput(DEBUG_LEVEL_VERBOSE,"lockCompareSwap64: node 0x%X, addr = 0x%016llX\n", + nodeId, addr); + debugOutput(DEBUG_LEVEL_VERBOSE," if (*(addr)==0x%016llX) *(addr)=0x%016llX\n", + compare_value, swap_value); + fb_octlet_t buffer; + if(!read_octlet( nodeId, addr,&buffer )) { + debugWarning("Could not read register\n"); + } else { + debugOutput(DEBUG_LEVEL_VERBOSE,"before = 0x%016llX\n", buffer); + } + #endif + + // do endiannes swapping + compare_value = CondSwapToBus64(compare_value); + swap_value = CondSwapToBus64(swap_value); + + // do separate locking here (no MutexLockHelper) since + // we use read_octlet in the DEBUG code in this function + m_handle_lock->Lock(); + int retval=raw1394_lock64(m_handle, nodeId, addr, + RAW1394_EXTCODE_COMPARE_SWAP, + swap_value, compare_value, result); + m_handle_lock->Unlock(); + + if(retval) { + debugError("raw1394_lock64 failed: %s\n", strerror(errno)); + } + + #ifdef DEBUG + if(!read_octlet( nodeId, addr,&buffer )) { + debugWarning("Could not read register\n"); + } else { + debugOutput(DEBUG_LEVEL_VERBOSE,"after = 0x%016llX\n", buffer); + } + #endif + + *result = CondSwapFromBus64(*result); + + return (retval == 0); +} + +fb_quadlet_t* +Ieee1394Service::transactionBlock( fb_nodeid_t nodeId, + fb_quadlet_t* buf, + int len, + unsigned int* resp_len ) +{ + // FIXME: simplify semantics + if (nodeId == INVALID_NODE_ID) { + debugWarning("operation on invalid node\n"); + return false; + } + // NOTE: this expects a call to transactionBlockClose to unlock + m_handle_lock->Lock(); + + // clear the request & response memory + memset(&m_fcp_block, 0, sizeof(m_fcp_block)); + + // make a local copy of the request + if(len < MAX_FCP_BLOCK_SIZE_QUADS) { + memcpy(m_fcp_block.request, buf, len*sizeof(quadlet_t)); + m_fcp_block.request_length = len; + } else { + debugWarning("Truncating FCP request\n"); + memcpy(m_fcp_block.request, buf, MAX_FCP_BLOCK_SIZE_BYTES); + m_fcp_block.request_length = MAX_FCP_BLOCK_SIZE_QUADS; + } + m_fcp_block.target_nodeid = 0xffc0 | nodeId; + + bool success = doFcpTransaction(); + if(success) { + *resp_len = m_fcp_block.response_length; + return m_fcp_block.response; + } else { + debugWarning("FCP transaction failed\n"); + *resp_len = 0; + return NULL; + } +} + +bool +Ieee1394Service::transactionBlockClose() +{ + m_handle_lock->Unlock(); + return true; +} + +// FCP code +bool +Ieee1394Service::doFcpTransaction() +{ + for(int i=0; i < IEEE1394SERVICE_FCP_MAX_TRIES; i++) { + if(doFcpTransactionTry()) { + return true; + } else { + debugOutput(DEBUG_LEVEL_VERBOSE, "FCP transaction try %d failed\n", i); + Util::SystemTimeSource::SleepUsecRelative( IEEE1394SERVICE_FCP_SLEEP_BETWEEN_FAILURES_USECS); + } + } + debugError("FCP transaction didn't succeed in %d tries\n", IEEE1394SERVICE_FCP_MAX_TRIES); + return false; +} + +#define FCP_COMMAND_ADDR 0xFFFFF0000B00ULL +#define FCP_RESPONSE_ADDR 0xFFFFF0000D00ULL + +/* AV/C FCP response codes */ +#define FCP_RESPONSE_NOT_IMPLEMENTED 0x08000000 +#define FCP_RESPONSE_ACCEPTED 0x09000000 +#define FCP_RESPONSE_REJECTED 0x0A000000 +#define FCP_RESPONSE_IN_TRANSITION 0x0B000000 +#define FCP_RESPONSE_IMPLEMENTED 0x0C000000 +#define FCP_RESPONSE_STABLE 0x0C000000 +#define FCP_RESPONSE_CHANGED 0x0D000000 +#define FCP_RESPONSE_INTERIM 0x0F000000 + +/* AV/C FCP mask macros */ +#define FCP_MASK_START(x) ((x) & 0xF0000000) +#define FCP_MASK_CTYPE(x) ((x) & 0x0F000000) +#define FCP_MASK_RESPONSE(x) ((x) & 0x0F000000) +#define FCP_MASK_SUBUNIT(x) ((x) & 0x00FF0000) +#define FCP_MASK_SUBUNIT_TYPE(x) ((x) & 0x00F80000) +#define FCP_MASK_SUBUNIT_ID(x) ((x) & 0x00070000) +#define FCP_MASK_OPCODE(x) ((x) & 0x0000FF00) +#define FCP_MASK_SUBUNIT_AND_OPCODE(x) ((x) & 0x00FFFF00) +#define FCP_MASK_OPERAND0(x) ((x) & 0x000000FF) +#define FCP_MASK_OPERAND(x, n) ((x) & (0xFF000000 >> ((((n)-1)%4)*8))) +#define FCP_MASK_RESPONSE_OPERAND(x, n) ((x) & (0xFF000000 >> (((n)%4)*8))) + +bool +Ieee1394Service::doFcpTransactionTry() +{ + // NOTE that access to this is protected by the m_handle lock + int err; + bool retval = true; + uint64_t timeout; + + // prepare an fcp response handler + raw1394_set_fcp_handler(m_handle, _avc_fcp_handler); + + // start listening for FCP requests + // this fails if some other program is listening for a FCP response + err = raw1394_start_fcp_listen(m_handle); + if(err) { + debugOutput(DEBUG_LEVEL_VERBOSE, "could not start FCP listen (err=%d, errno=%d)\n", err, errno); + retval = false; + goto out; + } + + m_fcp_block.status = eFS_Waiting; + + #ifdef DEBUG + debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"fcp request: node 0x%hX, length = %d bytes\n", + m_fcp_block.target_nodeid, m_fcp_block.request_length*4); + printBuffer(DEBUG_LEVEL_VERY_VERBOSE, m_fcp_block.request_length, m_fcp_block.request ); + #endif + + // write the FCP request + if(!writeNoLock( m_fcp_block.target_nodeid, FCP_COMMAND_ADDR, + m_fcp_block.request_length, m_fcp_block.request)) { + debugOutput(DEBUG_LEVEL_VERBOSE, "write of FCP request failed\n"); + retval = false; + goto out; + } + + // wait for the response to arrive + struct pollfd raw1394_poll; + raw1394_poll.fd = raw1394_get_fd(m_handle); + raw1394_poll.events = POLLIN; + + timeout = Util::SystemTimeSource::getCurrentTimeAsUsecs() + + IEEE1394SERVICE_FCP_RESPONSE_TIMEOUT_USEC; + + while(m_fcp_block.status == eFS_Waiting + && Util::SystemTimeSource::getCurrentTimeAsUsecs() < timeout) { + if(poll( &raw1394_poll, 1, IEEE1394SERVICE_FCP_POLL_TIMEOUT_MSEC) > 0) { + if (raw1394_poll.revents & POLLIN) { + raw1394_loop_iterate(m_handle); + } + } + } + + // stop listening for FCP responses + err = raw1394_stop_fcp_listen(m_handle); + if(err) { + debugOutput(DEBUG_LEVEL_VERBOSE, "could not stop FCP listen (err=%d, errno=%d)\n", err, errno); + retval = false; + goto out; + } + + // check the request and figure out what happened + if(m_fcp_block.status == eFS_Waiting) { + debugOutput(DEBUG_LEVEL_VERBOSE, "FCP response timed out\n"); + retval = false; + goto out; + } + if(m_fcp_block.status == eFS_Error) { + debugError("FCP request/response error\n"); + retval = false; + goto out; + } + +out: + m_fcp_block.status = eFS_Empty; + return retval; +} + +int +Ieee1394Service::_avc_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, + int response, size_t length, + unsigned char *data) +{ + Ieee1394Service *service = static_cast(raw1394_get_userdata(handle)); + if(service) { + return service->handleFcpResponse(nodeid, response, length, data); + } else return -1; +} + +int +Ieee1394Service::handleFcpResponse(nodeid_t nodeid, + int response, size_t length, + unsigned char *data) +{ + static struct sFcpBlock fcp_block_last; + + fb_quadlet_t *data_quads = (fb_quadlet_t *)data; + #ifdef DEBUG + debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"fcp response: node 0x%hX, response = %d, length = %d bytes\n", + nodeid, response, length); + printBuffer(DEBUG_LEVEL_VERY_VERBOSE, (length+3)/4, data_quads ); + #endif + + if (response && length > 3) { + if(length > MAX_FCP_BLOCK_SIZE_BYTES) { + length = MAX_FCP_BLOCK_SIZE_BYTES; + debugWarning("Truncated FCP response\n"); + } + + // is it an actual response or is it INTERIM? + quadlet_t first_quadlet = CondSwapFromBus32(data_quads[0]); + if(FCP_MASK_RESPONSE(first_quadlet) == FCP_RESPONSE_INTERIM) { + debugOutput(DEBUG_LEVEL_VERBOSE, "INTERIM\n"); + } else { + // it's an actual response, check if it matches our request + if(nodeid != m_fcp_block.target_nodeid) { + debugOutput(DEBUG_LEVEL_VERBOSE, "FCP response node id's don't match! (%x, %x)\n", + m_fcp_block.target_nodeid, nodeid); + } else if (first_quadlet == 0) { + debugWarning("Bogus FCP response\n"); + printBuffer(DEBUG_LEVEL_WARNING, (length+3)/4, data_quads ); +#ifdef DEBUG + } else if(FCP_MASK_RESPONSE(first_quadlet) < 0x08000000) { + debugWarning("Bogus AV/C FCP response code\n"); + printBuffer(DEBUG_LEVEL_WARNING, (length+3)/4, data_quads ); +#endif + } else if(FCP_MASK_SUBUNIT_AND_OPCODE(first_quadlet) + != FCP_MASK_SUBUNIT_AND_OPCODE(CondSwapFromBus32(m_fcp_block.request[0]))) { + debugOutput(DEBUG_LEVEL_VERBOSE, "FCP response not for this request: %08lX != %08lX\n", + FCP_MASK_SUBUNIT_AND_OPCODE(first_quadlet), + FCP_MASK_SUBUNIT_AND_OPCODE(CondSwapFromBus32(m_fcp_block.request[0]))); + } else if(m_filterFCPResponse && (memcmp(fcp_block_last.response, data, length) == 0)) { + // This is workaround for the Edirol FA-101. The device tends to send more than + // one responde to one request. This seems to happen when discovering + // function blocks and looks very likely there is a race condition in the + // device. The workaround here compares the just arrived FCP responde + // to the last one. If it is the same as the previously one then we + // just ignore it. The downside of this approach is, we cannot issue + // the same FCP twice. + debugWarning("Received duplicate FCP response. Ignore it\n"); + } else { + m_fcp_block.response_length = (length + sizeof(quadlet_t) - 1) / sizeof(quadlet_t); + memcpy(m_fcp_block.response, data, length); + if (m_filterFCPResponse) { + memcpy(fcp_block_last.response, data, length); + } + m_fcp_block.status = eFS_Responded; + } + } + } + return 0; +} + +bool +Ieee1394Service::setSplitTimeoutUsecs(fb_nodeid_t nodeId, unsigned int timeout) +{ + Util::MutexLockHelper lock(*m_handle_lock); + debugOutput(DEBUG_LEVEL_VERBOSE, "setting SPLIT_TIMEOUT on node 0x%X to %uusecs...\n", nodeId, timeout); + unsigned int secs = timeout / 1000000; + unsigned int usecs = timeout % 1000000; + + quadlet_t split_timeout_hi = CondSwapToBus32(secs & 7); + quadlet_t split_timeout_low = CondSwapToBus32(((usecs / 125) & 0x1FFF) << 19); + + // write the CSR registers + if(!writeNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_HI, 1, + &split_timeout_hi)) { + debugOutput(DEBUG_LEVEL_VERBOSE, "write of CSR_SPLIT_TIMEOUT_HI failed\n"); + return false; + } + if(!writeNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_LO, 1, + &split_timeout_low)) { + debugOutput(DEBUG_LEVEL_VERBOSE, "write of CSR_SPLIT_TIMEOUT_LO failed\n"); + return false; + } + return true; +} + +int +Ieee1394Service::getSplitTimeoutUsecs(fb_nodeid_t nodeId) +{ + Util::MutexLockHelper lock(*m_handle_lock); + quadlet_t split_timeout_hi; + quadlet_t split_timeout_low; + + debugOutput(DEBUG_LEVEL_VERBOSE, "reading SPLIT_TIMEOUT on node 0x%X...\n", nodeId); + + if(!readNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_HI, 1, + &split_timeout_hi)) { + debugOutput(DEBUG_LEVEL_VERBOSE, "read of CSR_SPLIT_TIMEOUT_HI failed\n"); + return 0; + } + debugOutput(DEBUG_LEVEL_VERBOSE, " READ HI: 0x%08lX\n", split_timeout_hi); + + if(!readNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_LO, 1, + &split_timeout_low)) { + debugOutput(DEBUG_LEVEL_VERBOSE, "read of CSR_SPLIT_TIMEOUT_LO failed\n"); + return 0; + } + debugOutput(DEBUG_LEVEL_VERBOSE, " READ LO: 0x%08lX\n", split_timeout_low); + + split_timeout_hi = CondSwapFromBus32(split_timeout_hi); + split_timeout_low = CondSwapFromBus32(split_timeout_low); + + return (split_timeout_hi & 7) * 1000000 + (split_timeout_low >> 19) * 125; +} + +void +Ieee1394Service::setFCPResponseFiltering(bool enable) +{ + m_filterFCPResponse = enable; +} + +int +Ieee1394Service::getVerboseLevel() +{ + return getDebugLevel(); +} + +void +Ieee1394Service::printBuffer( unsigned int level, size_t length, fb_quadlet_t* buffer ) const +{ + + for ( unsigned int i=0; i < length; ++i ) { + if ( ( i % 4 ) == 0 ) { + if ( i > 0 ) { + debugOutputShort(level,"\n"); + } + debugOutputShort(level," %4d: ",i*4); + } + debugOutputShort(level,"%08X ",buffer[i]); + } + debugOutputShort(level,"\n"); +} +void +Ieee1394Service::printBufferBytes( unsigned int level, size_t length, byte_t* buffer ) const +{ + + for ( unsigned int i=0; i < length; ++i ) { + if ( ( i % 16 ) == 0 ) { + if ( i > 0 ) { + debugOutputShort(level,"\n"); + } + debugOutputShort(level," %4d: ",i*16); + } + debugOutputShort(level,"%02X ",buffer[i]); + } + debugOutputShort(level,"\n"); +} + +int +Ieee1394Service::resetHandlerLowLevel( raw1394handle_t handle, + unsigned int generation ) +{ + raw1394_update_generation ( handle, generation ); + Ieee1394Service* instance + = (Ieee1394Service*) raw1394_get_userdata( handle ); + instance->resetHandler( generation ); + + return 0; +} + +bool +Ieee1394Service::resetHandler( unsigned int generation ) +{ + quadlet_t buf=0; + + m_handle_lock->Lock(); + raw1394_update_generation(m_handle, generation); + m_handle_lock->Unlock(); + + // do a simple read on ourself in order to update the internal structures + // this avoids failures after a bus reset + read_quadlet( getLocalNodeId() | 0xFFC0, + CSR_REGISTER_BASE | CSR_CYCLE_TIME, + &buf ); + + for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin(); + it != m_busResetHandlers.end(); + ++it ) + { + Util::Functor* func = *it; + ( *func )(); + } + + return true; +} + +bool +Ieee1394Service::startRHThread() +{ + int i; + + if ( m_threadRunning ) { + return true; + } + m_RHThread_lock->Lock(); + i = pthread_create( &m_thread, 0, rHThread, this ); + m_RHThread_lock->Unlock(); + if (i) { + debugFatal("Could not start ieee1394 service thread\n"); + return false; + } + m_threadRunning = true; + + return true; +} + +void +Ieee1394Service::stopRHThread() +{ + if ( m_threadRunning ) { + // wait for the thread to finish it's work + m_RHThread_lock->Lock(); + pthread_cancel (m_thread); + pthread_join (m_thread, 0); + m_RHThread_lock->Unlock(); + m_threadRunning = false; + } +} + +void* +Ieee1394Service::rHThread( void* arg ) +{ + Ieee1394Service* pIeee1394Service = (Ieee1394Service*) arg; + + while (true) { + // protect ourselves from dying + { + // use a scoped lock such that it is unlocked + // even if we are cancelled while running + // FIXME: check if this is true! +// Util::MutexLockHelper lock(*(pIeee1394Service->m_RHThread_lock)); + raw1394_loop_iterate (pIeee1394Service->m_resetHandle); + } + pthread_testcancel (); + } + + return 0; +} + +bool +Ieee1394Service::addBusResetHandler( Util::Functor* functor ) +{ + debugOutput(DEBUG_LEVEL_VERBOSE, "Adding busreset handler (%p)\n", functor); + m_busResetHandlers.push_back( functor ); + return true; +} + +bool +Ieee1394Service::remBusResetHandler( Util::Functor* functor ) +{ + debugOutput(DEBUG_LEVEL_VERBOSE, "Removing busreset handler (%p)\n", functor); + + for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin(); + it != m_busResetHandlers.end(); + ++it ) + { + if ( *it == functor ) { + debugOutput(DEBUG_LEVEL_VERBOSE, " found\n"); + m_busResetHandlers.erase( it ); + return true; + } + } + debugOutput(DEBUG_LEVEL_VERBOSE, " not found\n"); + return false; +} + +/** + * Allocates an iso channel for use by the interface in a similar way to + * libiec61883. Returns -1 on error (due to there being no free channels) + * or an allocated channel number. + * + * Does not perform anything other than registering the channel and the + * bandwidth at the IRM + * + * Also allocates the necessary bandwidth (in ISO allocation units). + * + * FIXME: As in libiec61883, channel 63 is not requested; this is either a + * bug or it's omitted since that's the channel preferred by video devices. + * + * @param bandwidth the bandwidth to allocate for this channel + * @return the channel number + */ +signed int Ieee1394Service::allocateIsoChannelGeneric(unsigned int bandwidth) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using generic method...\n" ); + + Util::MutexLockHelper lock(*m_handle_lock); + struct ChannelInfo cinfo; + + int c = -1; + for (c = 0; c < 63; c++) { + if (raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_ALLOC) == 0) + break; + } + if (c < 63) { + if (raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_ALLOC) < 0) { + debugFatal("Could not allocate bandwidth of %d\n", bandwidth); + + raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE); + return -1; + } else { + cinfo.channel=c; + cinfo.bandwidth=bandwidth; + cinfo.alloctype=AllocGeneric; + + cinfo.xmit_node=-1; + cinfo.xmit_plug=-1; + cinfo.recv_node=-1; + cinfo.recv_plug=-1; + + if (registerIsoChannel(c, cinfo)) { + return c; + } else { + raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_FREE); + raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE); + return -1; + } + } + } + return -1; +} + +/** + * Allocates an iso channel for use by the interface in a similar way to + * libiec61883. Returns -1 on error (due to there being no free channels) + * or an allocated channel number. + * + * Uses IEC61883 Connection Management Procedure to establish the connection. + * + * Also allocates the necessary bandwidth (in ISO allocation units). + * + * @param xmit_node node id of the transmitter + * @param xmit_plug the output plug to use. If -1, find the first online plug, and + * upon return, contains the plug number used. + * @param recv_node node id of the receiver + * @param recv_plug the input plug to use. If -1, find the first online plug, and + * upon return, contains the plug number used. + * + * @return the channel number + */ + +signed int Ieee1394Service::allocateIsoChannelCMP( + nodeid_t xmit_node, int xmit_plug, + nodeid_t recv_node, int recv_plug + ) { + + if (xmit_node == INVALID_NODE_ID) { + debugWarning("operation on invalid node (XMIT)\n"); + return -1; + } + if (recv_node == INVALID_NODE_ID) { + debugWarning("operation on invalid node (RECV)\n"); + return -1; + } + + debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using IEC61883 CMP...\n" ); + Util::MutexLockHelper lock(*m_handle_lock); + + struct ChannelInfo cinfo; + + int c = -1; + int bandwidth=1; + #if IEEE1394SERVICE_SKIP_IEC61883_BANDWIDTH_ALLOCATION + bandwidth=0; + #endif + + // do connection management: make connection + c = iec61883_cmp_connect( + m_handle, + xmit_node | 0xffc0, + &xmit_plug, + recv_node | 0xffc0, + &recv_plug, + &bandwidth); + + if((c<0) || (c>63)) { + debugError("Could not do CMP from %04X:%02d to %04X:%02d\n", + xmit_node, xmit_plug, recv_node, recv_plug + ); + return -1; + } + + cinfo.channel=c; + cinfo.bandwidth=bandwidth; + cinfo.alloctype=AllocCMP; + + cinfo.xmit_node=xmit_node; + cinfo.xmit_plug=xmit_plug; + cinfo.recv_node=recv_node; + cinfo.recv_plug=recv_plug; + + if (registerIsoChannel(c, cinfo)) { + return c; + } + + return -1; +} + +/** + * Deallocates an iso channel. Silently ignores a request to deallocate + * a negative channel number. + * + * Figures out the method that was used to allocate the channel (generic, cmp, ...) + * and uses the appropriate method to deallocate. Also frees the bandwidth + * that was reserved along with this channel. + * + * @param c channel number + * @return true if successful + */ +bool Ieee1394Service::freeIsoChannel(signed int c) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Freeing ISO channel %d...\n", c ); + Util::MutexLockHelper lock(*m_handle_lock); + + if (c < 0 || c > 63) { + debugWarning("Invalid channel number: %d\n", c); + return false; + } + + switch (m_channels[c].alloctype) { + default: + debugError(" BUG: invalid allocation type!\n"); + return false; + + case AllocFree: + debugWarning(" Channel %d not registered\n", c); + return false; + + case AllocGeneric: + debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using generic routine...\n" ); + debugOutput(DEBUG_LEVEL_VERBOSE, " freeing %d bandwidth units...\n", m_channels[c].bandwidth ); + if (raw1394_bandwidth_modify(m_handle, m_channels[c].bandwidth, RAW1394_MODIFY_FREE) !=0) { + debugWarning("Failed to deallocate bandwidth\n"); + } + debugOutput(DEBUG_LEVEL_VERBOSE, " freeing channel %d...\n", m_channels[c].channel ); + if (raw1394_channel_modify (m_handle, m_channels[c].channel, RAW1394_MODIFY_FREE) != 0) { + debugWarning("Failed to free channel\n"); + } + if (!unregisterIsoChannel(c)) + return false; + return true; + + case AllocCMP: + debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using IEC61883 CMP...\n" ); + debugOutput(DEBUG_LEVEL_VERBOSE, " performing IEC61883 CMP disconnect...\n" ); + if(iec61883_cmp_disconnect( + m_handle, + m_channels[c].xmit_node | 0xffc0, + m_channels[c].xmit_plug, + m_channels[c].recv_node | 0xffc0, + m_channels[c].recv_plug, + m_channels[c].channel, + m_channels[c].bandwidth) != 0) { + debugWarning("Could not do CMP disconnect for channel %d!\n",c); + } + if (!unregisterIsoChannel(c)) + return false; + return true; + } + + // unreachable + debugError("BUG: unreachable code reached!\n"); + + return false; +} + +/** + * Registers a channel as managed by this ieee1394service + * @param c channel number + * @param cinfo channel info struct + * @return true if successful + */ +bool Ieee1394Service::registerIsoChannel(unsigned int c, struct ChannelInfo cinfo) { + if (c < 63) { + if (m_channels[c].alloctype != AllocFree) { + debugWarning("Channel %d already registered with bandwidth %d\n", + m_channels[c].channel, m_channels[c].bandwidth); + } + + memcpy(&m_channels[c], &cinfo, sizeof(struct ChannelInfo)); + + } else return false; + return true; +} + +/** + * unegisters a channel from this ieee1394service + * @param c channel number + * @return true if successful + */ +bool Ieee1394Service::unregisterIsoChannel(unsigned int c) { + if (c < 63) { + if (m_channels[c].alloctype == AllocFree) { + debugWarning("Channel %d not registered\n", c); + return false; + } + + m_channels[c].channel=-1; + m_channels[c].bandwidth=-1; + m_channels[c].alloctype=AllocFree; + m_channels[c].xmit_node=0xFFFF; + m_channels[c].xmit_plug=-1; + m_channels[c].recv_node=0xFFFF; + m_channels[c].recv_plug=-1; + + } else return false; + return true; +} + +/** + * Returns the current value of the `bandwidth available' register on + * the IRM, or -1 on error. + * @return + */ +signed int Ieee1394Service::getAvailableBandwidth() { + quadlet_t buffer; + Util::MutexLockHelper lock(*m_handle_lock); + signed int result = raw1394_read (m_handle, raw1394_get_irm_id (m_handle), + CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE, + sizeof (quadlet_t), &buffer); + + if (result < 0) + return -1; + return CondSwapFromBus32(buffer); +} + +void +Ieee1394Service::setVerboseLevel(int l) +{ + if (m_pIsoManager) m_pIsoManager->setVerboseLevel(l); + if (m_pCTRHelper) m_pCTRHelper->setVerboseLevel(l); + if (m_pWatchdog) m_pWatchdog->setVerboseLevel(l); + setDebugLevel(l); + debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l ); +} + +void +Ieee1394Service::show() +{ + #ifdef DEBUG + uint32_t cycle_timer; + uint64_t local_time; + if(!readCycleTimerReg(&cycle_timer, &local_time)) { + debugWarning("Could not read cycle timer register\n"); + + } + uint64_t ctr = CYCLE_TIMER_TO_TICKS( cycle_timer ); + + debugOutput( DEBUG_LEVEL_VERBOSE, "Port: %d\n", getPort() ); + debugOutput( DEBUG_LEVEL_VERBOSE, " Name: %s\n", getPortName().c_str() ); + debugOutput( DEBUG_LEVEL_VERBOSE, " CycleTimerHelper: %p, IsoManager: %p, WatchDog: %p\n", + m_pCTRHelper, m_pIsoManager, m_pWatchdog ); + debugOutput( DEBUG_LEVEL_VERBOSE, " Time: %011llu (%03us %04ucy %04uticks)\n", + ctr, + (unsigned int)TICKS_TO_SECS( ctr ), + (unsigned int)TICKS_TO_CYCLES( ctr ), + (unsigned int)TICKS_TO_OFFSET( ctr ) ); + debugOutputShort( DEBUG_LEVEL_NORMAL, "Iso handler info:\n"); + #endif + if (m_pIsoManager) m_pIsoManager->dumpInfo(); +} Index: /tags/2.0-rc2/src/libieee1394/IEC61883.cpp =================================================================== --- /tags/2.0-rc2/src/libieee1394/IEC61883.cpp (revision 864) +++ /tags/2.0-rc2/src/libieee1394/IEC61883.cpp (revision 864) @@ -0,0 +1,34 @@ +/* + * 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 . + * + */ + +#include "IEC61883.h" + +IMPL_DEBUG_MODULE( IEC61883, IEC61883, DEBUG_LEVEL_NORMAL ); + +IEC61883::IEC61883() { + +} + +IEC61883::~IEC61883() { + +} Index: /tags/2.0-rc2/src/libieee1394/ieee1394service.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/ieee1394service.h (revision 1451) +++ /tags/2.0-rc2/src/libieee1394/ieee1394service.h (revision 1451) @@ -0,0 +1,458 @@ +/* + * 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 . + * + */ + +#ifndef FFADO_IEEE1394SERVICE_H +#define FFADO_IEEE1394SERVICE_H + +#include "fbtypes.h" +#include "libutil/Functors.h" +#include "libutil/Mutex.h" + +#include "debugmodule/debugmodule.h" + +#include "IEC61883.h" + +#include +#include + +#include +#include + +#define MAX_FCP_BLOCK_SIZE_BYTES (512) +#define MAX_FCP_BLOCK_SIZE_QUADS (MAX_FCP_BLOCK_SIZE_BYTES / 4) + +class IsoHandlerManager; +class CycleTimerHelper; + +namespace Util { + class Watchdog; + class Configuration; +} + +class Ieee1394Service : public IEC61883 { +public: + Ieee1394Service(); + Ieee1394Service(bool rt, int prio); + ~Ieee1394Service(); + + bool initialize( int port ); + bool setThreadParameters(bool rt, int priority); + Util::Watchdog *getWatchdog() {return m_pWatchdog;}; + + /** + * @brief get number of ports (firewire adapters) in this machine + * + * @return the number of ports + */ + static int detectNbPorts(); + + /** + * @brief get port (adapter) id + * + * @return get port (adapter) id + */ + int getPort() + { return m_port; } + + /** + * @brief get port (adapter) name + * + * @return get port (adapter) name + */ + std::string getPortName() + { return m_portName; }; + + /** + * @brief get number of nodes on the bus + * + * Since the root node always has + * the highest node ID, this number can be used to determine that ID (it's + * LOCAL_BUS|(count-1)). + * + * @return the number of nodes on the bus to which the port is connected. + * This value can change with every bus reset. + */ + int getNodeCount(); + + /** + * @brief get the node id of the local node + * + * @note does not include the bus part (0xFFC0) + * + * @return the node id of the local node + * This value can change with every bus reset. + */ + nodeid_t getLocalNodeId(); + + /** + * @brief get the most recent cycle timer value (in ticks) + * + * @note Uses the most appropriate method for getting the cycle timer + * which is not necessarily a direct read (could be DLL) + */ + uint32_t getCycleTimerTicks(); + + /** + * @brief get the most recent cycle timer value (in CTR format) + * + * @note Uses the most appropriate method for getting the cycle timer + * which is not necessarily a direct read (could be DLL) + */ + uint32_t getCycleTimer(); + + /** + * @brief get the cycle timer value for a specific time instant (in ticks) + * + * @note Uses the most appropriate method for getting the cycle timer + * which is not necessarily a direct read (could be DLL) + */ + uint32_t getCycleTimerTicks(uint64_t t); + + /** + * @brief get the cycle timer value for a specific time instant (in CTR format) + * + * @note Uses the most appropriate method for getting the cycle timer + * which is not necessarily a direct read (could be DLL) + */ + uint32_t getCycleTimer(uint64_t t); + + /** + * @brief get the system time for a specific cycle timer value (in ticks) + * @note thread safe + */ + uint64_t getSystemTimeForCycleTimerTicks(uint32_t ticks); + + /** + * @brief get the system time for a specific cycle timer value (in CTR format) + * @note thread safe + */ + uint64_t getSystemTimeForCycleTimer(uint32_t ctr); + + /** + * @brief read the cycle timer value from the controller (in CTR format) + * + * @note Uses a direct method to read the value from the controller + * @return true if successful + */ + bool readCycleTimerReg(uint32_t *cycle_timer, uint64_t *local_time); + + /** + * @brief provide the current system time + * @return + */ + uint64_t getCurrentTimeAsUsecs(); + + /** + * @brief send async read request to a node and wait for response. + * + * This does the complete transaction and will return when it's finished. + * + * @param node target node (\todo needs 0xffc0 stuff) + * @param addr address to read from + * @param length amount of data to read in quadlets + * @param buffer pointer to buffer where data will be saved + * + * @return true on success or false on failure (sets errno) + */ + bool read( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* buffer ); + + bool read_quadlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_quadlet_t* buffer ); + + bool read_octlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_octlet_t* buffer ); + + /** + * @brief send async write request to a node and wait for response. + * + * This does the complete transaction and will return when it's finished. + * + * @param node target node (\XXX needs 0xffc0 stuff) + * @param addr address to write to + * @param length amount of data to write in quadlets + * @param data pointer to data to be sent + * + * @return true on success or false on failure (sets errno) + */ + bool write( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* data ); + + bool write_quadlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_quadlet_t data ); + + bool write_octlet( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_octlet_t data ); + + /** + * @brief send 64-bit compare-swap lock request and wait for response. + * + * swaps the content of \ref addr with \ref swap_value , but only if + * the content of \ref addr equals \ref compare_with + * + * @note takes care of endiannes + * + * @param nodeId target node ID + * @param addr address within target node address space + * @param compare_with value to compare \ref addr with + * @param swap_value new value to put in \ref addr + * @param result the value (originally) in \ref addr + * + * @return true if succesful, false otherwise + */ + bool lockCompareSwap64( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + fb_octlet_t compare_value, + fb_octlet_t swap_value, + fb_octlet_t* result ); + + /** + * initiate AV/C transaction + * @param nodeId + * @param buf + * @param len + * @param resp_len + * @return + */ + fb_quadlet_t* transactionBlock( fb_nodeid_t nodeId, + fb_quadlet_t* buf, + int len, + unsigned int* resp_len ); + + /** + * close AV/C transaction. + * @param nodeId + * @param buf + * @param len + * @param resp_len + * @return + */ + bool transactionBlockClose(); + + int getVerboseLevel(); + + bool addBusResetHandler( Util::Functor* functor ); + bool remBusResetHandler( Util::Functor* functor ); + + void doBusReset(); + bool waitForBusResetStormToEnd( int nb_tries, int sleep_time_ms ); + + /** + * @brief get the current generation + * + * @return the current generation + **/ + unsigned int getGeneration() { + Util::MutexLockHelper lock(*m_handle_lock); + return raw1394_get_generation( m_handle ); + } + + /** + * @brief update the current generation + * + * @return the current generation + **/ + void updateGeneration() { + Util::MutexLockHelper lock(*m_handle_lock); + raw1394_update_generation( m_handle, getGeneration()); + } + + /** + * @brief sets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers + * + * sets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers on node + * nodeId such that the timeout is equal to timeout + * + * @param nodeId node to set CSR registers on + * @param timeout timeout in usecs + * @return true if successful + */ + bool setSplitTimeoutUsecs(fb_nodeid_t nodeId, unsigned int timeout); + + /** + * @brief gets the SPLIT_TIMEOUT_X timeout value + * + * gets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers on node + * nodeId and recombine them into one usec value + * + * @param nodeId node to get CSR registers from + * @return timeout in usecs if successful, 0 else + */ + int getSplitTimeoutUsecs(fb_nodeid_t nodeId); + + /** + * @brief use the provided configuration for this service + * + * only update the config once, before init. not thread safe, + * and no effect when things are already running. + * + * @param c configuration to use + * @return bool if this config is ok. + */ + bool useConfiguration(Util::Configuration *c); + + Util::Configuration *getConfiguration() {return m_configuration;}; + + /** + * @brief enable or disable FCP response doublicate filtering + * + * this is use only for devices (e.g. edirol fa101) which have a + * buggy FCP implementation and send more then one FCP response + * for one request. + */ + void setFCPResponseFiltering(bool enable); + +// ISO channel stuff +public: + signed int getAvailableBandwidth(); + signed int allocateIsoChannelGeneric(unsigned int bandwidth); + signed int allocateIsoChannelCMP(nodeid_t xmit_node, int xmit_plug, + nodeid_t recv_node, int recv_plug); + bool freeIsoChannel(signed int channel); + + IsoHandlerManager& getIsoHandlerManager() {return *m_pIsoManager;}; +private: + enum EAllocType { + AllocFree = 0, // not allocated (by us) + AllocGeneric = 1, // allocated with generic functions + AllocCMP=2 // allocated with CMP + }; + + struct ChannelInfo { + int channel; + int bandwidth; + enum EAllocType alloctype; + nodeid_t xmit_node; + int xmit_plug; + nodeid_t recv_node; + int recv_plug; + }; + + // the info for the channels we manage + struct ChannelInfo m_channels[64]; + + bool unregisterIsoChannel(unsigned int c); + bool registerIsoChannel(unsigned int c, struct ChannelInfo cinfo); + +public: +// FIXME: should be private, but is used to do the PCR control in GenericAVC::AvDevice + raw1394handle_t getHandle() {return m_handle;}; + +protected: + Util::Configuration *m_configuration; + +private: + bool configurationUpdated(); + + bool startRHThread(); + void stopRHThread(); + static void* rHThread( void* arg ); + + void printBuffer( unsigned int level, size_t length, fb_quadlet_t* buffer ) const; + void printBufferBytes( unsigned int level, size_t length, byte_t* buffer ) const; + + static int resetHandlerLowLevel( raw1394handle_t handle, + unsigned int generation ); + bool resetHandler( unsigned int generation ); + + raw1394handle_t m_handle; + Util::Mutex* m_handle_lock; + raw1394handle_t m_resetHandle; + raw1394handle_t m_util_handle; // a handle for operations from the rt thread + int m_port; + std::string m_portName; + + pthread_t m_thread; + Util::Mutex* m_RHThread_lock; + bool m_threadRunning; + + bool m_realtime; + int m_base_priority; + + IsoHandlerManager* m_pIsoManager; + CycleTimerHelper* m_pCTRHelper; + bool m_have_new_ctr_read; + + bool m_filterFCPResponse; + + // the RT watchdog + Util::Watchdog* m_pWatchdog; + + typedef std::vector< Util::Functor* > reset_handler_vec_t; + reset_handler_vec_t m_busResetHandlers; + + // unprotected variants + bool writeNoLock( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* data ); + bool readNoLock( fb_nodeid_t nodeId, + fb_nodeaddr_t addr, + size_t length, + fb_quadlet_t* buffer ); + + // FCP transaction support + static int _avc_fcp_handler(raw1394handle_t handle, nodeid_t nodeid, + int response, size_t length, + unsigned char *data); + int handleFcpResponse(nodeid_t nodeid, + int response, size_t length, + unsigned char *data); + + enum eFcpStatus { + eFS_Empty, + eFS_Waiting, + eFS_Responded, + eFS_Error, + }; + + struct sFcpBlock { + enum eFcpStatus status; + nodeid_t target_nodeid; + unsigned int request_length; + quadlet_t request[MAX_FCP_BLOCK_SIZE_QUADS]; + unsigned int response_length; + quadlet_t response[MAX_FCP_BLOCK_SIZE_QUADS]; + }; + struct sFcpBlock m_fcp_block; + + bool doFcpTransaction(); + bool doFcpTransactionTry(); + +public: + void setVerboseLevel(int l); + void show(); +private: + DECLARE_DEBUG_MODULE; +}; + +#endif // FFADO_IEEE1394SERVICE_H Index: /tags/2.0-rc2/src/libieee1394/IEC61883.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/IEC61883.h (revision 864) +++ /tags/2.0-rc2/src/libieee1394/IEC61883.h (revision 864) @@ -0,0 +1,204 @@ +/* + * 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 . + * + */ + +#ifndef __FFADO_IEC61883__ +#define __FFADO_IEC61883__ + +#include "../debugmodule/debugmodule.h" + +/* + * This is shamelessly stolen from iec61883-private, + * but I need these functions! + * FIXME: this will only work until somebody decides to change + * these in libiec61883. + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Plug Control Registers + **/ + +/* maximum number of PCRs allowed within the standard + * MPR/PCR addresses defined in IEC-61883. + * This refers to the number of output or input PCRs-- + * not the MPRs and not the combined total. + */ +#define IEC61883_PCR_MAX 31 + +/* standard CSR offsets for plugs */ +#define CSR_O_MPR 0x900 +#define CSR_O_PCR_0 0x904 + +#define CSR_I_MPR 0x980 +#define CSR_I_PCR_0 0x984 + +#if ( __BYTE_ORDER == __BIG_ENDIAN ) + +struct iec61883_oMPR { + unsigned int data_rate:2; + unsigned int bcast_channel:6; + unsigned int non_persist_ext:8; + unsigned int persist_ext:8; + unsigned int reserved:3; + unsigned int n_plugs:5; +}; + +struct iec61883_iMPR { + unsigned int data_rate:2; + unsigned int reserved:6; + unsigned int non_persist_ext:8; + unsigned int persist_ext:8; + unsigned int reserved2:3; + unsigned int n_plugs:5; +}; + +struct iec61883_oPCR { + unsigned int online:1; + unsigned int bcast_connection:1; + unsigned int n_p2p_connections:6; + unsigned int reserved:2; + unsigned int channel:6; + unsigned int data_rate:2; + unsigned int overhead_id:4; + unsigned int payload:10; +}; + +struct iec61883_iPCR { + unsigned int online:1; + unsigned int bcast_connection:1; + unsigned int n_p2p_connections:6; + unsigned int reserved:2; + unsigned int channel:6; + unsigned int reserved2:16; +}; + +#else + +struct iec61883_oMPR { + unsigned int n_plugs:5; + unsigned int reserved:3; + unsigned int persist_ext:8; + unsigned int non_persist_ext:8; + unsigned int bcast_channel:6; + unsigned int data_rate:2; +}; + +struct iec61883_iMPR { + unsigned int n_plugs:5; + unsigned int reserved2:3; + unsigned int persist_ext:8; + unsigned int non_persist_ext:8; + unsigned int reserved:6; + unsigned int data_rate:2; +}; + +struct iec61883_oPCR { + unsigned int payload:10; + unsigned int overhead_id:4; + unsigned int data_rate:2; + unsigned int channel:6; + unsigned int reserved:2; + unsigned int n_p2p_connections:6; + unsigned int bcast_connection:1; + unsigned int online:1; +}; + +struct iec61883_iPCR { + unsigned int reserved2:16; + unsigned int channel:6; + unsigned int reserved:2; + unsigned int n_p2p_connections:6; + unsigned int bcast_connection:1; + unsigned int online:1; +}; + +#endif + +/** + * iec61883_plug_get - Read a node's plug register. + * @h: A raw1394 handle. + * @n: The node id of the node to read + * @a: The CSR offset address (relative to base) of the register to read. + * @value: A pointer to a quadlet where the plug register's value will be stored. + * + * This function handles bus to host endian conversion. It returns 0 for + * suceess or -1 for error (errno available). + **/ +int +iec61883_plug_get(raw1394handle_t h, nodeid_t n, nodeaddr_t a, quadlet_t *value); + + +/** + * iec61883_plug_set - Write a node's plug register. + * @h: A raw1394 handle. + * @n: The node id of the node to read + * @a: The CSR offset address (relative to CSR base) of the register to write. + * @value: A quadlet containing the new register value. + * + * This uses a compare/swap lock operation to safely write the + * new register value, as required by IEC 61883-1. + * This function handles host to bus endian conversion. It returns 0 for success + * or -1 for error (errno available). + **/ +int +iec61883_plug_set(raw1394handle_t h, nodeid_t n, nodeaddr_t a, quadlet_t value); + +/** + * High level plug access macros + */ + +#define iec61883_get_oMPR(h,n,v) iec61883_plug_get((h), (n), CSR_O_MPR, (quadlet_t *)(v)) +#define iec61883_set_oMPR(h,n,v) iec61883_plug_set((h), (n), CSR_O_MPR, *((quadlet_t *)&(v))) +#define iec61883_get_oPCR0(h,n,v) iec61883_plug_get((h), (n), CSR_O_PCR_0, (quadlet_t *)(v)) +#define iec61883_set_oPCR0(h,n,v) iec61883_plug_set((h), (n), CSR_O_PCR_0, *((quadlet_t *)&(v))) +#define iec61883_get_oPCRX(h,n,v,x) iec61883_plug_get((h), (n), CSR_O_PCR_0+(4*(x)), (quadlet_t *)(v)) +#define iec61883_set_oPCRX(h,n,v,x) iec61883_plug_set((h), (n), CSR_O_PCR_0+(4*(x)), *((quadlet_t *)&(v))) +#define iec61883_get_iMPR(h,n,v) iec61883_plug_get((h), (n), CSR_I_MPR, (quadlet_t *)(v)) +#define iec61883_set_iMPR(h,n,v) iec61883_plug_set((h), (n), CSR_I_MPR, *((quadlet_t *)&(v))) +#define iec61883_get_iPCR0(h,n,v) iec61883_plug_get((h), (n), CSR_I_PCR_0, (quadlet_t *)(v)) +#define iec61883_set_iPCR0(h,n,v) iec61883_plug_set((h), (n), CSR_I_PCR_0, *((quadlet_t *)&(v))) +#define iec61883_get_iPCRX(h,n,v,x) iec61883_plug_get((h), (n), CSR_I_PCR_0+(4*(x)), (quadlet_t *)(v)) +#define iec61883_set_iPCRX(h,n,v,x) iec61883_plug_set((h), (n), CSR_I_PCR_0+(4*(x)), *((quadlet_t *)&(v))) + + +#ifdef __cplusplus +} +#endif + +class IEC61883 { + +public: + + IEC61883(); + virtual ~IEC61883(); + +protected: + DECLARE_DEBUG_MODULE; + +}; + +#endif /* __FFADO_IEC61883__ */ + + Index: /tags/2.0-rc2/src/libieee1394/vendor_model_ids.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/vendor_model_ids.h (revision 864) +++ /tags/2.0-rc2/src/libieee1394/vendor_model_ids.h (revision 864) @@ -0,0 +1,46 @@ +/* + * 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 . + * + */ + +#ifndef VENDOR_MODEL_IDS +#define VENDOR_MODEL_IDS + +#define FW_VENDORID_TERRATEC 0x000aac +#define FW_VENDORID_MACKIE 0x00000f +#define FW_VENDORID_APOGEE 0x0003db +#define FW_VENDORID_BRIDGECO 0x0007f5 +#define FW_VENDORID_PRESONUS 0x000a92 +#define FW_VENDORID_ESI 0x000f1b +#define FW_VENDORID_FOCUSRITE 0x00130e +#define FW_VENDORID_EDIROL 0x0040ab +#define FW_VENDORID_MAUDIO 0x000d6c +#define FW_VENDORID_ECHO 0x001486 +#define FW_VENDORID_RME 0x000a35 +#define FW_VENDORID_MOTU 0x0001f2 +#define FW_VENDORID_TCAT 0x000166 + +// this is the one we assign ourselves +// maybe once we can get a real one :) +#define FW_VENDORID_FFADO 0x0B0001 + + +#endif /* VENDOR_MODEL_IDS */ Index: /tags/2.0-rc2/src/libieee1394/configrom.cpp =================================================================== --- /tags/2.0-rc2/src/libieee1394/configrom.cpp (revision 1292) +++ /tags/2.0-rc2/src/libieee1394/configrom.cpp (revision 1292) @@ -0,0 +1,672 @@ +/* + * Copyright (C) 2005-2008 by Daniel Wagner + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#include "configrom.h" +#include "ieee1394service.h" + +#include "vendor_model_ids.h" + +#include "libutil/SystemTimeSource.h" + +#include +#include + +#include +#include + +using namespace std; + +IMPL_DEBUG_MODULE( ConfigRom, ConfigRom, DEBUG_LEVEL_NORMAL ); + +static int busRead( struct csr1212_csr* csr, + u_int64_t addr, + u_int16_t length, + void* buffer, + void* private_data ); + +static int getMaxRom( u_int32_t* bus_info_data, + void* private_data ); + +static struct csr1212_bus_ops configrom_csr1212_ops = { + busRead, + 0, + 0, + getMaxRom +}; + +struct config_csr_info { + Ieee1394Service* service; + fb_nodeid_t nodeId; +}; + +//------------------------------------------------------------- + +ConfigRom::ConfigRom( Ieee1394Service& ieee1394service, fb_nodeid_t nodeId ) + : Control::Element(NULL, "ConfigRom") + , m_1394Service( ieee1394service ) + , m_nodeId( nodeId ) + , m_avcDevice( false ) // FIXME: this does not seem veryu + , m_guid( 0 ) + , m_vendorName( "" ) + , m_modelName( "" ) + , m_vendorId( 0 ) + , m_modelId( 0 ) + , m_unit_specifier_id( 0 ) + , m_unit_version( 0 ) + , m_isIsoResourceManager( false ) + , m_isCycleMasterCapable( false ) + , m_isSupportIsoOperations( false ) + , m_isBusManagerCapable( false ) + , m_cycleClkAcc( 0 ) + , m_maxRec( 0 ) + , m_nodeVendorId( 0 ) + , m_chipIdHi( 0 ) + , m_chipIdLow( 0 ) + , m_vendorNameKv( 0 ) + , m_modelNameKv( 0 ) + , m_csr( 0 ) +{ +} + +ConfigRom::ConfigRom() + : Control::Element(NULL, "ConfigRom") + , m_1394Service( *(new Ieee1394Service()) ) + , m_nodeId( -1 ) + , m_avcDevice( false ) // FIXME: this does not seem veryu + , m_guid( 0 ) + , m_vendorName( "" ) + , m_modelName( "" ) + , m_vendorId( 0 ) + , m_modelId( 0 ) + , m_unit_specifier_id( 0 ) + , m_unit_version( 0 ) + , m_isIsoResourceManager( false ) + , m_isCycleMasterCapable( false ) + , m_isSupportIsoOperations( false ) + , m_isBusManagerCapable( false ) + , m_cycleClkAcc( 0 ) + , m_maxRec( 0 ) + , m_nodeVendorId( 0 ) + , m_chipIdHi( 0 ) + , m_chipIdLow( 0 ) + , m_vendorNameKv( 0 ) + , m_modelNameKv( 0 ) + , m_csr( 0 ) +{ +} + +Ieee1394Service& +ConfigRom::get1394Service() +{ + return m_1394Service; +} + +bool +ConfigRom::operator == ( const ConfigRom& rhs ) +{ + return m_guid == rhs.m_guid; +} + +bool +ConfigRom::compareGUID( const ConfigRom& a, const ConfigRom& b ) { + return a.getGuid() > b.getGuid(); +} + +bool +ConfigRom::initialize() +{ + struct config_csr_info csr_info; + csr_info.service = &m_1394Service; + csr_info.nodeId = 0xffc0 | m_nodeId; + + m_csr = csr1212_create_csr( &configrom_csr1212_ops, + 5 * sizeof(fb_quadlet_t), // XXX Why 5 ?!? + &csr_info ); + if (!m_csr || csr1212_parse_csr( m_csr ) != CSR1212_SUCCESS) { + debugError( "Could not parse config rom of node %d on port %d\n", m_nodeId, m_1394Service.getPort() ); + if (m_csr) { + csr1212_destroy_csr(m_csr); + m_csr = 0; + } + return false; + } + + // Process Bus_Info_Block + m_isIsoResourceManager = CSR1212_BE32_TO_CPU(m_csr->bus_info_data[2] ) >> 31; + m_isCycleMasterCapable = ( CSR1212_BE32_TO_CPU(m_csr->bus_info_data[2] ) >> 30 ) & 0x1; + m_isSupportIsoOperations = ( CSR1212_BE32_TO_CPU(m_csr->bus_info_data[2] ) >> 29 ) & 0x1; + m_isBusManagerCapable = ( CSR1212_BE32_TO_CPU(m_csr->bus_info_data[2] ) >> 28 ) & 0x1; + m_cycleClkAcc = ( CSR1212_BE32_TO_CPU(m_csr->bus_info_data[2] ) >> 16 ) & 0xff; + m_maxRec = ( CSR1212_BE32_TO_CPU( m_csr->bus_info_data[2] ) >> 12 ) & 0xf; + m_nodeVendorId = ( CSR1212_BE32_TO_CPU( m_csr->bus_info_data[3] ) >> 8 ); + m_chipIdHi = ( CSR1212_BE32_TO_CPU( m_csr->bus_info_data[3] ) ) & 0xff; + m_chipIdLow = CSR1212_BE32_TO_CPU( m_csr->bus_info_data[4] ); + + // Process Root Directory + processRootDirectory(m_csr); + + if ( m_vendorNameKv ) { + int len = ( m_vendorNameKv->value.leaf.len - 2) * sizeof( quadlet_t ); + char* buf = new char[len+2]; + memcpy( buf, + ( void* )CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA( m_vendorNameKv ), + len ); + + while ((buf + len - 1) == '\0') { + len--; + } + // \todo XXX seems a bit strage to do this but the nodemgr.c code does + // it. try to figure out why this is needed (or not) + buf[len++] = ' '; + buf[len] = '\0'; + + + debugOutput( DEBUG_LEVEL_VERBOSE, "Vendor name: '%s'\n", buf ); + m_vendorName = buf; + delete[] buf; + } + if ( m_modelNameKv ) { + int len = ( m_modelNameKv->value.leaf.len - 2) * sizeof( quadlet_t ); + char* buf = new char[len+2]; + memcpy( buf, + ( void* )CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA( m_modelNameKv ), + len ); + while ((buf + len - 1) == '\0') { + len--; + } + // \todo XXX for edirol fa-66 it seems somehow broken. see above + // todo as well. + buf[len++] = ' '; + buf[len] = '\0'; + + debugOutput( DEBUG_LEVEL_VERBOSE, "Model name: '%s'\n", buf); + m_modelName = buf; + delete[] buf; + } + + m_guid = ((u_int64_t)CSR1212_BE32_TO_CPU(m_csr->bus_info_data[3]) << 32) + | CSR1212_BE32_TO_CPU(m_csr->bus_info_data[4]); + + if ( m_vendorNameKv ) { + csr1212_release_keyval( m_vendorNameKv ); + m_vendorNameKv = 0; + } + if ( m_modelNameKv ) { + csr1212_release_keyval( m_modelNameKv ); + m_modelNameKv = 0; + } + if ( m_csr ) { + csr1212_destroy_csr(m_csr); + m_csr = 0; + } + return true; +} + +static int +busRead( struct csr1212_csr* csr, + u_int64_t addr, + u_int16_t length, + void* buffer, + void* private_data ) +{ + struct config_csr_info* csr_info = (struct config_csr_info*) private_data; + + int nb_retries = 5; + + while ( nb_retries-- + && !csr_info->service->read( csr_info->nodeId, + addr, + (size_t)length/4, + ( quadlet_t* )buffer) ) + {// failed, retry + Util::SystemTimeSource::SleepUsecRelative(IEEE1394SERVICE_CONFIGROM_READ_WAIT_USECS); + } + Util::SystemTimeSource::SleepUsecRelative(IEEE1394SERVICE_CONFIGROM_READ_WAIT_USECS); + + if (nb_retries > -1) return 0; // success + else return -1; // failure +} + +static int +getMaxRom( u_int32_t* bus_info_data, + void* /*private_data*/) +{ + return (CSR1212_BE32_TO_CPU( bus_info_data[2] ) >> 8) & 0x3; +} + + +void +ConfigRom::processUnitDirectory( struct csr1212_csr* csr, + struct csr1212_keyval* ud_kv, + unsigned int *id ) +{ + struct csr1212_dentry *dentry; + struct csr1212_keyval *kv; + unsigned int last_key_id = 0; + + debugOutput( DEBUG_LEVEL_VERBOSE, "process unit directory:\n" ); + csr1212_for_each_dir_entry(csr, kv, ud_kv, dentry) { + switch (kv->key.id) { + case CSR1212_KV_ID_VENDOR: + if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { + debugOutput( DEBUG_LEVEL_VERBOSE, + "\tvendor_id = 0x%08x\n", + kv->value.immediate); + m_vendorId = kv->value.immediate; + } + break; + + case CSR1212_KV_ID_MODEL: + debugOutput( DEBUG_LEVEL_VERBOSE, + "\tmodel_id = 0x%08x\n", + kv->value.immediate); + m_modelId = kv->value.immediate; + break; + + case CSR1212_KV_ID_SPECIFIER_ID: + debugOutput( DEBUG_LEVEL_VERBOSE, + "\tspecifier_id = 0x%08x\n", + kv->value.immediate); + m_unit_specifier_id = kv->value.immediate; + break; + + case CSR1212_KV_ID_VERSION: + debugOutput( DEBUG_LEVEL_VERBOSE, + "\tversion = 0x%08x\n", + kv->value.immediate); + m_unit_version = kv->value.immediate; + if ( m_unit_specifier_id == 0x0000a02d ) // XXX + { + m_avcDevice = true; // FIXME: disable this check for the moment + if ( kv->value.immediate == 0x14001 ) { + m_avcDevice = true; + } + } + break; + + case CSR1212_KV_ID_DESCRIPTOR: + if (kv->key.type == CSR1212_KV_TYPE_LEAF && + CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && + CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) + { + switch (last_key_id) { + case CSR1212_KV_ID_VENDOR: + csr1212_keep_keyval(kv); + m_vendorNameKv = kv; + break; + + case CSR1212_KV_ID_MODEL: + m_modelNameKv = kv; + csr1212_keep_keyval(kv); + break; + + } + } /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */ + break; + + case CSR1212_KV_ID_DEPENDENT_INFO: + if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { + /* This should really be done in SBP2 as this is + * doing SBP2 specific parsing. */ + processUnitDirectory(csr, kv, id); + } + + break; + + default: + break; + } + last_key_id = kv->key.id; + } +} + +void +ConfigRom::processRootDirectory(struct csr1212_csr* csr) +{ + unsigned int ud_id = 0; + struct csr1212_dentry *dentry; + struct csr1212_keyval *kv; + unsigned int last_key_id = 0; + + csr1212_for_each_dir_entry(csr, kv, csr->root_kv, dentry) { + switch (kv->key.id) { + case CSR1212_KV_ID_VENDOR: + debugOutput( DEBUG_LEVEL_VERBOSE, + "vendor id = 0x%08x\n", kv->value.immediate); + break; + + case CSR1212_KV_ID_NODE_CAPABILITIES: + debugOutput( DEBUG_LEVEL_VERBOSE, + "capabilities = 0x%08x\n", kv->value.immediate); + break; + + case CSR1212_KV_ID_UNIT: + processUnitDirectory(csr, kv, &ud_id); + break; + + case CSR1212_KV_ID_DESCRIPTOR: + if (last_key_id == CSR1212_KV_ID_VENDOR) { + if (kv->key.type == CSR1212_KV_TYPE_LEAF && + CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 && + CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 && + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) + { + m_vendorNameKv = kv; + csr1212_keep_keyval(kv); + } + } + break; + } + last_key_id = kv->key.id; + } + +} + +const fb_nodeid_t +ConfigRom::getNodeId() const +{ + return m_nodeId; +} + +const fb_octlet_t +ConfigRom::getGuid() const +{ + return m_guid; +} + +const std::string +ConfigRom::getGuidString() const +{ + char* buf; + asprintf( &buf, "%08x%08x", + ( unsigned int ) ( getGuid() >> 32 ), + ( unsigned int ) ( getGuid() & 0xffffffff ) ); + std::string result = buf; + free( buf ); + return result; +} + +const std::string +ConfigRom::getModelName() const +{ + // HACK: + // workarounds for devices that don't fill a correct model name + switch(m_vendorId) { + case FW_VENDORID_MOTU: + switch(m_unit_specifier_id) { + case 0x00000003: + return "828MkII"; + case 0x00000009: + return "Traveler"; + case 0x0000000d: + return "UltraLite"; + case 0x0000000f: + return "8pre"; + case 0x00000001: + return "828MkI"; + case 0x00000005: + return "896HD"; + default: + return "unknown"; + } + break; + default: + return m_modelName; + } +} + +const std::string +ConfigRom::getVendorName() const +{ + // HACK: + // workarounds for devices that don't fill a correct vendor name + switch(m_vendorId) { + case FW_VENDORID_MOTU: + return "MOTU"; + default: + return m_vendorName; + } +} + +const unsigned int +ConfigRom::getModelId() const +{ + return m_modelId; +} + +const unsigned int +ConfigRom::getVendorId() const +{ + return m_vendorId; +} + +const unsigned int +ConfigRom::getUnitSpecifierId() const +{ + return m_unit_specifier_id; +} + +const unsigned int +ConfigRom::getUnitVersion() const +{ + return m_unit_version; +} + +bool +ConfigRom::updatedNodeId() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, + "Checking for updated node id for device with GUID 0x%016llX...\n", + getGuid()); + + struct csr1212_csr* csr = NULL; + for ( fb_nodeid_t nodeId = 0; + nodeId < m_1394Service.getNodeCount(); + ++nodeId ) + { + struct config_csr_info csr_info; + csr_info.service = &m_1394Service; + csr_info.nodeId = 0xffc0 | nodeId; + debugOutput( DEBUG_LEVEL_VERBOSE, "Looking at node %d...\n", nodeId); + + csr = csr1212_create_csr( &configrom_csr1212_ops, + 5 * sizeof(fb_quadlet_t), // XXX Why 5 ?!? + &csr_info ); + + if (!csr || csr1212_parse_csr( csr ) != CSR1212_SUCCESS) { + debugWarning( "Failed to get/parse CSR\n"); + if (csr) { + csr1212_destroy_csr(csr); + csr = NULL; + } + continue; + } + + octlet_t guid = + ((u_int64_t)CSR1212_BE32_TO_CPU(csr->bus_info_data[3]) << 32) + | CSR1212_BE32_TO_CPU(csr->bus_info_data[4]); + + debugOutput( DEBUG_LEVEL_VERBOSE, + " Node has GUID 0x%016llX\n", + guid); + + if ( guid == getGuid() ) { + debugOutput( DEBUG_LEVEL_VERBOSE, "GUID matches ours\n"); + if ( nodeId != getNodeId() ) { + debugOutput( DEBUG_LEVEL_VERBOSE, + "Device with GUID 0x%016llX changed node id " + "from %d to %d\n", + getGuid(), + getNodeId(), + nodeId ); + m_nodeId = nodeId; + } else { + debugOutput( DEBUG_LEVEL_VERBOSE, + "Device with GUID 0x%016llX kept node id %d\n", + getGuid(), + getNodeId()); + } + if (csr) { + csr1212_destroy_csr(csr); + csr = NULL; + } + return true; + } + } + + if (csr) { + csr1212_destroy_csr(csr); + } + + debugOutput( DEBUG_LEVEL_VERBOSE, + "Device with GUID 0x%016llX could not be found on " + "the bus anymore (removed?)\n", + getGuid() ); + m_nodeId = INVALID_NODE_ID; + return false; +} + +void +ConfigRom::printConfigRomDebug() const +{ + using namespace std; + debugOutput(DEBUG_LEVEL_NORMAL, "Config ROM\n" ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tCurrent Node Id:\t%d\n", getNodeId() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tGUID:\t\t\t0x%016llX\n", getGuid()); + debugOutput(DEBUG_LEVEL_NORMAL, "\tVendor Name:\t\t%s\n", getVendorName().c_str() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tModel Name:\t\t%s\n", getModelName().c_str() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tNode Vendor ID:\t\t0x%06x\n", getNodeVendorId() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tModel Id:\t\t0x%08x\n", getModelId() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tUnit Specifier ID:\t0x%06x\n", getUnitSpecifierId() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tUnit version:\t\t0x%08x\n", getUnitVersion() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tISO resource manager:\t%d\n", isIsoResourseManager() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tCycle master capable:\t%d\n", isSupportsIsoOperations() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tBus manager capable:\t%d\n", isBusManagerCapable() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tCycle clock accuracy:\t%d\n", getCycleClockAccurancy() ); + debugOutput(DEBUG_LEVEL_NORMAL, "\tMax rec:\t\t%d (max asy payload: %d bytes)\n", + getMaxRec(), getAsyMaxPayload() ); +} + +void +ConfigRom::printConfigRom() const +{ + using namespace std; + printMessage("Config ROM\n" ); + printMessage("\tCurrent Node Id:\t%d\n", getNodeId() ); + printMessage("\tGUID:\t\t\t0x%016llX\n", getGuid()); + printMessage("\tVendor Name:\t\t%s\n", getVendorName().c_str() ); + printMessage("\tModel Name:\t\t%s\n", getModelName().c_str() ); + printMessage("\tNode Vendor ID:\t\t0x%06x\n", getNodeVendorId() ); + printMessage("\tModel Id:\t\t0x%08x\n", getModelId() ); + printMessage("\tUnit Specifier ID:\t0x%06x\n", getUnitSpecifierId() ); + printMessage("\tUnit version:\t\t0x%08x\n", getUnitVersion() ); + printMessage("\tISO resource manager:\t%d\n", isIsoResourseManager() ); + printMessage("\tCycle master capable:\t%d\n", isSupportsIsoOperations() ); + printMessage("\tBus manager capable:\t%d\n", isBusManagerCapable() ); + printMessage("\tCycle clock accuracy:\t%d\n", getCycleClockAccurancy() ); + printMessage("\tMax rec:\t\t%d (max asy payload: %d bytes)\n", getMaxRec(), getAsyMaxPayload() ); +} + +unsigned short +ConfigRom::getAsyMaxPayload() const +{ + // XXX use pow instead? + return 1 << ( m_maxRec + 1 ); +} + +bool +ConfigRom::serialize( std::string path, Util::IOSerialize& ser ) +{ + bool result; + result = ser.write( path + "m_nodeId", m_nodeId ); + result &= ser.write( path + "m_avcDevice", m_avcDevice ); + result &= ser.write( path + "m_guid", m_guid ); + result &= ser.write( path + "m_vendorName", std::string( m_vendorName ) ); + result &= ser.write( path + "m_modelName", std::string( m_modelName ) ); + result &= ser.write( path + "m_vendorId", m_vendorId ); + result &= ser.write( path + "m_modelId", m_modelId ); + result &= ser.write( path + "m_unit_specifier_id", m_unit_specifier_id ); + result &= ser.write( path + "m_unit_version", m_unit_version ); + result &= ser.write( path + "m_isIsoResourceManager", m_isIsoResourceManager ); + result &= ser.write( path + "m_isCycleMasterCapable", m_isCycleMasterCapable ); + result &= ser.write( path + "m_isSupportIsoOperations", m_isSupportIsoOperations ); + result &= ser.write( path + "m_isBusManagerCapable", m_isBusManagerCapable ); + result &= ser.write( path + "m_cycleClkAcc", m_cycleClkAcc ); + result &= ser.write( path + "m_maxRec", m_maxRec ); + result &= ser.write( path + "m_nodeVendorId", m_nodeVendorId ); + result &= ser.write( path + "m_chipIdHi", m_chipIdHi ); + result &= ser.write( path + "m_chipIdLow", m_chipIdLow ); + return result; +} + +ConfigRom* +ConfigRom::deserialize( std::string path, Util::IODeserialize& deser, Ieee1394Service& ieee1394Service ) +{ + ConfigRom* pConfigRom = new ConfigRom; + if ( !pConfigRom ) { + return 0; + } + + pConfigRom->m_1394Service = ieee1394Service; + + bool result; + result = deser.read( path + "m_nodeId", pConfigRom->m_nodeId ); + result &= deser.read( path + "m_avcDevice", pConfigRom->m_avcDevice ); + result &= deser.read( path + "m_guid", pConfigRom->m_guid ); + result &= deser.read( path + "m_vendorName", pConfigRom->m_vendorName ); + result &= deser.read( path + "m_modelName", pConfigRom->m_modelName ); + result &= deser.read( path + "m_vendorId", pConfigRom->m_vendorId ); + result &= deser.read( path + "m_modelId", pConfigRom->m_modelId ); + result &= deser.read( path + "m_unit_specifier_id", pConfigRom->m_unit_specifier_id ); + result &= deser.read( path + "m_unit_version", pConfigRom->m_unit_version ); + result &= deser.read( path + "m_isIsoResourceManager", pConfigRom->m_isIsoResourceManager ); + result &= deser.read( path + "m_isCycleMasterCapable", pConfigRom->m_isCycleMasterCapable ); + result &= deser.read( path + "m_isSupportIsoOperations", pConfigRom->m_isSupportIsoOperations ); + result &= deser.read( path + "m_isBusManagerCapable", pConfigRom->m_isBusManagerCapable ); + result &= deser.read( path + "m_cycleClkAcc", pConfigRom->m_cycleClkAcc ); + result &= deser.read( path + "m_maxRec", pConfigRom->m_maxRec ); + result &= deser.read( path + "m_nodeVendorId", pConfigRom->m_nodeVendorId ); + result &= deser.read( path + "m_chipIdHi", pConfigRom->m_chipIdHi ); + result &= deser.read( path + "m_chipIdLow", pConfigRom->m_chipIdLow ); + + if ( !result ) { + delete pConfigRom; + return 0; + } + + return pConfigRom; +} + +bool +ConfigRom::setNodeId( fb_nodeid_t nodeId ) +{ + m_nodeId = nodeId; + return true; +} Index: /tags/2.0-rc2/src/libieee1394/IsoHandlerManager.cpp =================================================================== --- /tags/2.0-rc2/src/libieee1394/IsoHandlerManager.cpp (revision 1536) +++ /tags/2.0-rc2/src/libieee1394/IsoHandlerManager.cpp (revision 1536) @@ -0,0 +1,1159 @@ +/* + * 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 . + * + */ + +#include "config.h" +#include "IsoHandlerManager.h" +#include "ieee1394service.h" +#include "cycletimer.h" +#include "libstreaming/generic/StreamProcessor.h" + +#include "libutil/Atomic.h" +#include "libutil/PosixThread.h" +#include "libutil/SystemTimeSource.h" +#include "libutil/Watchdog.h" +#include "libutil/Configuration.h" + +#include +#include + +IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL ); +IMPL_DEBUG_MODULE( IsoTask, IsoTask, DEBUG_LEVEL_NORMAL ); + +using namespace Streaming; + +// --- ISO Thread --- // + +IsoTask::IsoTask(IsoHandlerManager& manager, enum IsoHandler::EHandlerType t) + : m_manager( manager ) + , m_SyncIsoHandler ( NULL ) + , m_handlerType( t ) + , m_running( false ) + , m_in_busreset( false ) + , m_activity_wait_timeout_nsec (ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS * 1000LL) +{ +} + +IsoTask::~IsoTask() +{ + sem_destroy(&m_activity_semaphore); +} + +bool +IsoTask::Init() +{ + request_update = 0; + + int i; + for (i=0; i < ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT; i++) { + m_IsoHandler_map_shadow[i] = NULL; + m_poll_fds_shadow[i].events = 0; + } + m_poll_nfds_shadow = 0; + + #ifdef DEBUG + m_last_loop_entry = 0; + m_successive_short_loops = 0; + #endif + + sem_init(&m_activity_semaphore, 0, 0); + m_running = true; + return true; +} + +void +IsoTask::requestShadowMapUpdate() +{ + debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) enter\n", this); + INC_ATOMIC(&request_update); + + // get the thread going again + signalActivity(); + debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) exit\n", this); +} + +bool +IsoTask::handleBusReset() +{ + bool retval = true; + m_in_busreset = true; + requestShadowMapUpdate(); + if(request_update) { + debugError("shadow map update request not honored\n"); + return false; + } + + unsigned int i, max; + max = m_manager.m_IsoHandlers.size(); + for (i = 0; i < max; i++) { + IsoHandler *h = m_manager.m_IsoHandlers.at(i); + assert(h); + + // skip the handlers not intended for us + if(h->getType() != m_handlerType) continue; + + if (!h->handleBusReset()) { + debugWarning("Failed to handle busreset on %p\n"); + retval = false; + } + } + + // re-enable processing + m_in_busreset = false; + requestShadowMapUpdate(); + if(request_update) { + debugError("shadow map update request not honored\n"); + return false; + } + return retval; +} + +// updates the internal stream map +// note that this should be executed with the guarantee that +// nobody will modify the parent data structures +void +IsoTask::updateShadowMapHelper() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) updating shadow vars...\n", this); + // we are handling a busreset + if(m_in_busreset) { + m_poll_nfds_shadow = 0; + return; + } + unsigned int i, cnt, max; + max = m_manager.m_IsoHandlers.size(); + m_SyncIsoHandler = NULL; + for (i = 0, cnt = 0; i < max; i++) { + IsoHandler *h = m_manager.m_IsoHandlers.at(i); + assert(h); + + // skip the handlers not intended for us + if(h->getType() != m_handlerType) continue; + + // update the state of the handler + // FIXME: maybe this is not the best place to do this + // it might be better to eliminate the 'requestShadowMapUpdate' + // entirely and replace it with a mechanism that implements all + // actions on the m_manager.m_IsoHandlers in the loop + h->updateState(); + + // rebuild the map + if (h->isEnabled()) { + m_IsoHandler_map_shadow[cnt] = h; + m_poll_fds_shadow[cnt].fd = h->getFileDescriptor(); + m_poll_fds_shadow[cnt].revents = 0; + m_poll_fds_shadow[cnt].events = POLLIN; + cnt++; + // FIXME: need a more generic approach here + if( m_SyncIsoHandler == NULL + && h->getType() == IsoHandler::eHT_Transmit) { + m_SyncIsoHandler = h; + } + + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) %s handler %p added\n", + this, h->getTypeString(), h); + } else { + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) %s handler %p skipped (disabled)\n", + this, h->getTypeString(), h); + } + if(cnt > ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT) { + debugWarning("Too much ISO Handlers in thread...\n"); + break; + } + } + + // FIXME: need a more generic approach here + // if there are no active transmit handlers, + // use the first receive handler + if( m_SyncIsoHandler == NULL + && m_poll_nfds_shadow) { + m_SyncIsoHandler = m_IsoHandler_map_shadow[0]; + } + m_poll_nfds_shadow = cnt; + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) updated shadow vars...\n", this); +} + +bool +IsoTask::Execute() +{ + debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, + "(%p, %s) Execute\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); + int err; + unsigned int i; + unsigned int m_poll_timeout = 10; + + #ifdef DEBUG + uint64_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs(); + int diff = now - m_last_loop_entry; + if(diff < 100) { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "(%p, %s) short loop detected (%d usec), cnt: %d\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"), + diff, m_successive_short_loops); + m_successive_short_loops++; + if(m_successive_short_loops > 10000) { + debugError("Shutting down runaway thread\n"); + m_running = false; + return false; + } + } else { + // reset the counter + m_successive_short_loops = 0; + } + m_last_loop_entry = now; + #endif + + // if some other thread requested a shadow map update, do it + if(request_update) { + updateShadowMapHelper(); + DEC_ATOMIC(&request_update); // ack the update + assert(request_update >= 0); + } + + // bypass if no handlers are registered + if (m_poll_nfds_shadow == 0) { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "(%p, %s) bypass iterate since no handlers to poll\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); + usleep(m_poll_timeout * 1000); + return true; + } + + // FIXME: what can happen is that poll() returns, but not all clients are + // ready. there might be some busy waiting behavior that still has to be solved. + + // setup the poll here + // we should prevent a poll() where no events are specified, since that will only time-out + bool no_one_to_poll = true; + while(no_one_to_poll) { + for (i = 0; i < m_poll_nfds_shadow; i++) { + short events = 0; + IsoHandler *h = m_IsoHandler_map_shadow[i]; + // we should only poll on a transmit handler + // that has a client that is ready to send + // something. Otherwise it will end up in + // busy wait looping since the packet function + // will defer processing (also avoids the + // AGAIN problem) + if (h->canIterateClient()) { + events = POLLIN | POLLPRI; + no_one_to_poll = false; + // if we are going to poll() it, let's ensure + // it can run until someone wants it to exit + h->allowIterateLoop(); + } + m_poll_fds_shadow[i].events = events; + } + + if(no_one_to_poll) { + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "(%p, %s) No one to poll, waiting for something to happen\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); + // wait for something to happen + switch(waitForActivity()) { + case IsoTask::eAR_Error: + debugError("Error while waiting for activity\n"); + return false; + case IsoTask::eAR_Interrupted: + // FIXME: what to do here? + debugWarning("Interrupted while waiting for activity\n"); + break; + case IsoTask::eAR_Timeout: + // FIXME: what to do here? + debugWarning("Timeout while waiting for activity\n"); + no_one_to_poll = false; // exit the loop to be able to detect failing handlers + break; + case IsoTask::eAR_Activity: + // do nothing + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "(%p, %s) something happened\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); + break; + } + } + } + + // Use a shadow map of the fd's such that we don't have to update + // the fd map everytime we run poll(). + err = poll (m_poll_fds_shadow, m_poll_nfds_shadow, m_poll_timeout); + uint32_t ctr_at_poll_return = m_manager.get1394Service().getCycleTimer(); + + if (err < 0) { + if (errno == EINTR) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Ignoring poll return due to signal\n"); + return true; + } + debugFatal("poll error: %s\n", strerror (errno)); + m_running = false; + return false; + } + + // find handlers that have died + uint64_t ctr_at_poll_return_ticks = CYCLE_TIMER_TO_TICKS(ctr_at_poll_return); + bool handler_died = false; + for (i = 0; i < m_poll_nfds_shadow; i++) { + // figure out if a handler has died + + // this is the time of the last packet we saw in the iterate() handler + uint32_t last_packet_seen = m_IsoHandler_map_shadow[i]->getLastPacketTime(); + if (last_packet_seen == 0xFFFFFFFF) { + // this was not iterated yet, so can't be dead + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, + "(%p, %s) handler %d didn't see any packets yet\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"), i); + continue; + } + + uint64_t last_packet_seen_ticks = CYCLE_TIMER_TO_TICKS(last_packet_seen); + // we use a relatively large value to distinguish between "death" and xrun + int64_t max_diff_ticks = TICKS_PER_SECOND * 2; + int64_t measured_diff_ticks = diffTicks(ctr_at_poll_return_ticks, last_packet_seen_ticks); + + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "(%p, %s) check handler %d: diff = %lld, max = %lld, now: %08lX, last: %08lX\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"), + i, measured_diff_ticks, max_diff_ticks, ctr_at_poll_return, last_packet_seen); + if(measured_diff_ticks > max_diff_ticks) { + debugFatal("(%p, %s) Handler died: now: %08lX, last: %08lX, diff: %lld (max: %lld)\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"), + ctr_at_poll_return, last_packet_seen, measured_diff_ticks, max_diff_ticks); + m_IsoHandler_map_shadow[i]->notifyOfDeath(); + handler_died = true; + } + } + + if(handler_died) { + m_running = false; + return false; // one or more handlers have died + } + + // iterate the handlers + for (i = 0; i < m_poll_nfds_shadow; i++) { + #ifdef DEBUG + if(m_poll_fds_shadow[i].revents) { + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "(%p, %s) received events: %08X for (%d/%d, %p, %s)\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive"), + m_poll_fds_shadow[i].revents, + i, m_poll_nfds_shadow, + m_IsoHandler_map_shadow[i], + m_IsoHandler_map_shadow[i]->getTypeString()); + } + #endif + + // if we get here, it means two things: + // 1) the kernel can accept or provide packets (poll returned POLLIN) + // 2) the client can provide or accept packets (since we enabled polling) + if(m_poll_fds_shadow[i].revents & (POLLIN)) { + m_IsoHandler_map_shadow[i]->iterate(ctr_at_poll_return); + } else { + // there might be some error condition + if (m_poll_fds_shadow[i].revents & POLLERR) { + debugWarning("(%p) error on fd for %d\n", this, i); + } + if (m_poll_fds_shadow[i].revents & POLLHUP) { + debugWarning("(%p) hangup on fd for %d\n", this, i); + } + } + } + return true; +} + +enum IsoTask::eActivityResult +IsoTask::waitForActivity() +{ + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "(%p, %s) waiting for activity\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); + struct timespec ts; + int result; + + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + debugError("clock_gettime failed\n"); + return eAR_Error; + } + + ts.tv_nsec += m_activity_wait_timeout_nsec; + while(ts.tv_nsec >= 1000000000LL) { + ts.tv_sec += 1; + ts.tv_nsec -= 1000000000LL; + } + + result = sem_timedwait(&m_activity_semaphore, &ts); + + if(result != 0) { + if (errno == ETIMEDOUT) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) sem_timedwait() timed out (result=%d)\n", + this, result); + return eAR_Timeout; + } else if (errno == EINTR) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) sem_timedwait() interrupted by signal (result=%d)\n", + this, result); + return eAR_Interrupted; + } else if (errno == EINVAL) { + debugError("(%p) sem_timedwait error (result=%d errno=EINVAL)\n", + this, result); + debugError("(%p) timeout_nsec=%lld ts.sec=%d ts.nsec=%lld\n", + this, m_activity_wait_timeout_nsec, ts.tv_sec, ts.tv_nsec); + return eAR_Error; + } else { + debugError("(%p) sem_timedwait error (result=%d errno=%d)\n", + this, result, errno); + debugError("(%p) timeout_nsec=%lld ts.sec=%d ts.nsec=%lld\n", + this, m_activity_wait_timeout_nsec, ts.tv_sec, ts.tv_nsec); + return eAR_Error; + } + } + + debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, + "(%p, %s) got activity\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); + return eAR_Activity; +} + +void +IsoTask::signalActivity() +{ + // signal the activity cond var + sem_post(&m_activity_semaphore); + debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE, + "(%p, %s) activity\n", + this, (m_handlerType == IsoHandler::eHT_Transmit? "Transmit": "Receive")); +} + +void IsoTask::setVerboseLevel(int i) { + setDebugLevel(i); + debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", i ); +} + +// -- the ISO handler manager -- // +IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service) + : m_State(E_Created) + , m_service( service ) + , m_realtime(false), m_priority(0) + , m_IsoThreadTransmit ( NULL ) + , m_IsoTaskTransmit ( NULL ) + , m_IsoThreadReceive ( NULL ) + , m_IsoTaskReceive ( NULL ) +{ +} + +IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio) + : m_State(E_Created) + , m_service( service ) + , m_realtime(run_rt), m_priority(rt_prio) + , m_IsoThreadTransmit ( NULL ) + , m_IsoTaskTransmit ( NULL ) + , m_IsoThreadReceive ( NULL ) + , m_IsoTaskReceive ( NULL ) +{ +} + +IsoHandlerManager::~IsoHandlerManager() +{ + stopHandlers(); + pruneHandlers(); + if(m_IsoHandlers.size() > 0) { + debugError("Still some handlers in use\n"); + } + if (m_IsoThreadTransmit) { + m_IsoThreadTransmit->Stop(); + delete m_IsoThreadTransmit; + } + if (m_IsoThreadReceive) { + m_IsoThreadReceive->Stop(); + delete m_IsoThreadReceive; + } + if (m_IsoTaskTransmit) { + delete m_IsoTaskTransmit; + } + if (m_IsoTaskReceive) { + delete m_IsoTaskReceive; + } +} + +bool +IsoHandlerManager::handleBusReset() +{ + debugOutput( DEBUG_LEVEL_NORMAL, "bus reset...\n"); + // A few things can happen on bus reset: + // 1) no devices added/removed => streams are still valid, but might have to be restarted + // 2) a device was removed => some streams become invalid + // 3) a device was added => same as 1, new device is ignored + if (!m_IsoTaskTransmit) { + debugError("No xmit task\n"); + return false; + } + if (!m_IsoTaskReceive) { + debugError("No receive task\n"); + return false; + } + if (!m_IsoTaskTransmit->handleBusReset()) { + debugWarning("could no handle busreset on xmit\n"); + } + if (!m_IsoTaskReceive->handleBusReset()) { + debugWarning("could no handle busreset on recv\n"); + } + return true; +} + +void +IsoHandlerManager::requestShadowMapUpdate() +{ + if(m_IsoTaskTransmit) m_IsoTaskTransmit->requestShadowMapUpdate(); + if(m_IsoTaskReceive) m_IsoTaskReceive->requestShadowMapUpdate(); +} + +bool +IsoHandlerManager::setThreadParameters(bool rt, int priority) { + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority); + if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority + if (priority < THREAD_MIN_RTPRIO) priority = THREAD_MIN_RTPRIO; // cap the priority + m_realtime = rt; + m_priority = priority; + + // grab the options from the parent + Util::Configuration *config = m_service.getConfiguration(); + int ihm_iso_prio_increase = ISOHANDLERMANAGER_ISO_PRIO_INCREASE; + int ihm_iso_prio_increase_xmit = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT; + int ihm_iso_prio_increase_recv = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV; + if(config) { + config->getValueForSetting("ieee1394.isomanager.prio_increase", ihm_iso_prio_increase); + config->getValueForSetting("ieee1394.isomanager.prio_increase_xmit", ihm_iso_prio_increase_xmit); + config->getValueForSetting("ieee1394.isomanager.prio_increase_recv", ihm_iso_prio_increase_recv); + } + + if (m_IsoThreadTransmit) { + if (m_realtime) { + m_IsoThreadTransmit->AcquireRealTime(m_priority + + ihm_iso_prio_increase + + ihm_iso_prio_increase_xmit); + } else { + m_IsoThreadTransmit->DropRealTime(); + } + } + if (m_IsoThreadReceive) { + if (m_realtime) { + m_IsoThreadReceive->AcquireRealTime(m_priority + + ihm_iso_prio_increase + + ihm_iso_prio_increase_recv); + } else { + m_IsoThreadReceive->DropRealTime(); + } + } + + return true; +} + +bool IsoHandlerManager::init() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this); + // check state + if(m_State != E_Created) { + debugError("Manager already initialized...\n"); + return false; + } + + // grab the options from the parent + Util::Configuration *config = m_service.getConfiguration(); + int ihm_iso_prio_increase = ISOHANDLERMANAGER_ISO_PRIO_INCREASE; + int ihm_iso_prio_increase_xmit = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT; + int ihm_iso_prio_increase_recv = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV; + int64_t isotask_activity_timeout_usecs = ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS; + if(config) { + config->getValueForSetting("ieee1394.isomanager.prio_increase", ihm_iso_prio_increase); + config->getValueForSetting("ieee1394.isomanager.prio_increase_xmit", ihm_iso_prio_increase_xmit); + config->getValueForSetting("ieee1394.isomanager.prio_increase_recv", ihm_iso_prio_increase_recv); + config->getValueForSetting("ieee1394.isomanager.isotask_activity_timeout_usecs", isotask_activity_timeout_usecs); + } + + // create threads to iterate our ISO handlers + debugOutput( DEBUG_LEVEL_VERBOSE, "Create iso thread for %p transmit...\n", this); + m_IsoTaskTransmit = new IsoTask( *this, IsoHandler::eHT_Transmit ); + if(!m_IsoTaskTransmit) { + debugFatal("No task\n"); + return false; + } + m_IsoTaskTransmit->setVerboseLevel(getDebugLevel()); + m_IsoTaskTransmit->m_activity_wait_timeout_nsec = isotask_activity_timeout_usecs * 1000LL; + m_IsoThreadTransmit = new Util::PosixThread(m_IsoTaskTransmit, "ISOXMT", m_realtime, + m_priority + ihm_iso_prio_increase + + ihm_iso_prio_increase_xmit, + PTHREAD_CANCEL_DEFERRED); + + if(!m_IsoThreadTransmit) { + debugFatal("No thread\n"); + return false; + } + m_IsoThreadTransmit->setVerboseLevel(getDebugLevel()); + + debugOutput( DEBUG_LEVEL_VERBOSE, "Create iso thread for %p receive...\n", this); + m_IsoTaskReceive = new IsoTask( *this, IsoHandler::eHT_Receive ); + if(!m_IsoTaskReceive) { + debugFatal("No task\n"); + return false; + } + m_IsoTaskReceive->setVerboseLevel(getDebugLevel()); + m_IsoThreadReceive = new Util::PosixThread(m_IsoTaskReceive, "ISORCV", m_realtime, + m_priority + ihm_iso_prio_increase + + ihm_iso_prio_increase_recv, + PTHREAD_CANCEL_DEFERRED); + + if(!m_IsoThreadReceive) { + debugFatal("No thread\n"); + return false; + } + m_IsoThreadReceive->setVerboseLevel(getDebugLevel()); + // register the thread with the RT watchdog + Util::Watchdog *watchdog = m_service.getWatchdog(); + if(watchdog) { + if(!watchdog->registerThread(m_IsoThreadTransmit)) { + debugWarning("could not register iso transmit thread with watchdog\n"); + } + if(!watchdog->registerThread(m_IsoThreadReceive)) { + debugWarning("could not register iso receive thread with watchdog\n"); + } + } else { + debugWarning("could not find valid watchdog\n"); + } + + if (m_IsoThreadTransmit->Start() != 0) { + debugFatal("Could not start ISO Transmit thread\n"); + return false; + } + if (m_IsoThreadReceive->Start() != 0) { + debugFatal("Could not start ISO Receive thread\n"); + return false; + } + + m_State=E_Running; + return true; +} + +void +IsoHandlerManager::signalActivityTransmit() +{ + assert(m_IsoTaskTransmit); + m_IsoTaskTransmit->signalActivity(); +} + +void +IsoHandlerManager::signalActivityReceive() +{ + assert(m_IsoTaskReceive); + m_IsoTaskReceive->signalActivity(); +} + +bool IsoHandlerManager::registerHandler(IsoHandler *handler) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); + assert(handler); + handler->setVerboseLevel(getDebugLevel()); + m_IsoHandlers.push_back(handler); + requestShadowMapUpdate(); + return true; +} + +bool IsoHandlerManager::unregisterHandler(IsoHandler *handler) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); + assert(handler); + + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if ( *it == handler ) { + m_IsoHandlers.erase(it); + requestShadowMapUpdate(); + return true; + } + } + debugFatal("Could not find handler (%p)\n", handler); + return false; //not found +} + +/** + * Registers an StreamProcessor with the IsoHandlerManager. + * + * If nescessary, an IsoHandler is created to handle this stream. + * Once an StreamProcessor is registered to the handler, it will be included + * in the ISO streaming cycle (i.e. receive/transmit of it will occur). + * + * @param stream the stream to register + * @return true if registration succeeds + * + * \todo : currently there is a one-to-one mapping + * between streams and handlers, this is not ok for + * multichannel receive + */ +bool IsoHandlerManager::registerStream(StreamProcessor *stream) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Registering %s stream %p\n", stream->getTypeString(), stream); + assert(stream); + + IsoHandler* h = NULL; + + // make sure the stream isn't already attached to a handler + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if((*it)->isStreamRegistered(stream)) { + debugError( "stream already registered!\n"); + return false; + } + } + + // clean up all handlers that aren't used + pruneHandlers(); + + // allocate a handler for this stream + if (stream->getType()==StreamProcessor::ePT_Receive) { + // grab the options from the parent + Util::Configuration *config = m_service.getConfiguration(); + int receive_mode_setting = DEFAULT_ISO_RECEIVE_MODE; + int bufferfill_mode_threshold = BUFFERFILL_MODE_THRESHOLD; + int min_interrupts_per_period = MINIMUM_INTERRUPTS_PER_PERIOD; + int max_nb_buffers_recv = MAX_RECV_NB_BUFFERS; + int min_packetsize_recv = MIN_RECV_PACKET_SIZE; + if(config) { + config->getValueForSetting("ieee1394.isomanager.iso_receive_mode", receive_mode_setting); + config->getValueForSetting("ieee1394.isomanager.bufferfill_mode_threshold", bufferfill_mode_threshold); + config->getValueForSetting("ieee1394.isomanager.min_interrupts_per_period", min_interrupts_per_period); + config->getValueForSetting("ieee1394.isomanager.max_nb_buffers_recv", max_nb_buffers_recv); + config->getValueForSetting("ieee1394.isomanager.min_packetsize_recv", min_packetsize_recv); + } + + // setup the optimal parameters for the raw1394 ISO buffering + unsigned int packets_per_period = stream->getPacketsPerPeriod(); + // reserve space for the 1394 header too (might not be necessary) + unsigned int max_packet_size = stream->getMaxPacketSize() + 8; + unsigned int page_size = getpagesize(); + + enum raw1394_iso_dma_recv_mode receive_mode; + switch(receive_mode_setting) { + case 0: + if(packets_per_period < (unsigned)bufferfill_mode_threshold) { + debugOutput( DEBUG_LEVEL_VERBOSE, "Using packet-per-buffer mode (auto) [%d, %d]\n", + packets_per_period, bufferfill_mode_threshold); + receive_mode = RAW1394_DMA_PACKET_PER_BUFFER; + } else { + debugOutput( DEBUG_LEVEL_VERBOSE, "Using bufferfill mode (auto) [%d, %d]\n", + packets_per_period, bufferfill_mode_threshold); + receive_mode = RAW1394_DMA_BUFFERFILL; + } + break; + case 1: + debugOutput( DEBUG_LEVEL_VERBOSE, "Using packet-per-buffer mode (config)\n"); + receive_mode = RAW1394_DMA_PACKET_PER_BUFFER; + break; + case 2: + debugOutput( DEBUG_LEVEL_VERBOSE, "Using bufferfill mode (config)\n"); + receive_mode = RAW1394_DMA_BUFFERFILL; + break; + default: debugWarning("Bogus receive mode setting in config: %d\n", receive_mode_setting); + } + + // Ensure we don't request a packet size bigger than the + // kernel-enforced maximum which is currently 1 page. + // NOTE: PP: this is not really true AFAICT + if (max_packet_size > page_size) { + debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size); + return false; + } + if (max_packet_size < (unsigned)min_packetsize_recv) { + debugError("min packet size (%u) < MIN_RECV_PACKET_SIZE (%u), using min value\n", + max_packet_size, min_packetsize_recv); + max_packet_size = min_packetsize_recv; + } + + // the interrupt/wakeup interval prediction of raw1394 is a mess... + int irq_interval = (packets_per_period-1) / min_interrupts_per_period; + if(irq_interval <= 0) irq_interval=1; + + // the receive buffer size doesn't matter for the latency, + // it does seem to be confined to a certain region for correct + // operation. However it is not clear how many. + int buffers = max_nb_buffers_recv; + + // ensure at least 2 hardware interrupts per ISO buffer wraparound + if(irq_interval > buffers/2) { + irq_interval = buffers/2; + } + + // create the actual handler + debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoRecvHandler\n"); + h = new IsoHandler(*this, IsoHandler::eHT_Receive, + buffers, max_packet_size, irq_interval); + + if(!h) { + debugFatal("Could not create IsoRecvHandler\n"); + return false; + } + + h->setReceiveMode(receive_mode); + + } else if (stream->getType()==StreamProcessor::ePT_Transmit) { + // grab the options from the parent + Util::Configuration *config = m_service.getConfiguration(); + int min_interrupts_per_period = MINIMUM_INTERRUPTS_PER_PERIOD; + int max_nb_buffers_xmit = MAX_XMIT_NB_BUFFERS; + int max_packetsize_xmit = MAX_XMIT_PACKET_SIZE; + int min_packetsize_xmit = MIN_XMIT_PACKET_SIZE; + if(config) { + config->getValueForSetting("ieee1394.isomanager.min_interrupts_per_period", min_interrupts_per_period); + config->getValueForSetting("ieee1394.isomanager.max_nb_buffers_xmit", max_nb_buffers_xmit); + config->getValueForSetting("ieee1394.isomanager.max_packetsize_xmit", max_packetsize_xmit); + config->getValueForSetting("ieee1394.isomanager.min_packetsize_xmit", min_packetsize_xmit); + } + + // setup the optimal parameters for the raw1394 ISO buffering + // reserve space for the 1394 header too (might not be necessary) + unsigned int max_packet_size = stream->getMaxPacketSize() + 8; + + if (max_packet_size > (unsigned)max_packetsize_xmit) { + debugError("max packet size (%u) > MAX_XMIT_PACKET_SIZE (%u)\n", + max_packet_size, max_packetsize_xmit); + return false; + } + if (max_packet_size < (unsigned)min_packetsize_xmit) { + debugError("min packet size (%u) < MIN_XMIT_PACKET_SIZE (%u), using min value\n", + max_packet_size, min_packetsize_xmit); + max_packet_size = min_packetsize_xmit; + } + + int buffers = max_nb_buffers_xmit; + unsigned int packets_per_period = stream->getPacketsPerPeriod(); + + int irq_interval = (packets_per_period-1) / min_interrupts_per_period; + if(irq_interval <= 0) irq_interval=1; + // ensure at least 2 hardware interrupts per ISO buffer wraparound + if(irq_interval > buffers/2) { + irq_interval = buffers/2; + } + + debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoXmitHandler\n"); + + // create the actual handler + h = new IsoHandler(*this, IsoHandler::eHT_Transmit, + buffers, max_packet_size, irq_interval); + + if(!h) { + debugFatal("Could not create IsoXmitHandler\n"); + return false; + } + + } else { + debugFatal("Bad stream type\n"); + return false; + } + + h->setVerboseLevel(getDebugLevel()); + + // register the stream with the handler + if(!h->registerStream(stream)) { + debugFatal("Could not register receive stream with handler\n"); + return false; + } + + // register the handler with the manager + if(!registerHandler(h)) { + debugFatal("Could not register receive handler with manager\n"); + return false; + } + debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n", stream, h); + + m_StreamProcessors.push_back(stream); + debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n", + m_StreamProcessors.size(), m_IsoHandlers.size()); + return true; +} + +bool IsoHandlerManager::unregisterStream(StreamProcessor *stream) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering %s stream %p\n", stream->getTypeString(), stream); + assert(stream); + + // make sure the stream isn't attached to a handler anymore + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if((*it)->isStreamRegistered(stream)) { + if(!(*it)->unregisterStream(stream)) { + debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it); + return false; + } + debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it); + } + } + + // clean up all handlers that aren't used + pruneHandlers(); + + // remove the stream from the registered streams list + for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin(); + it != m_StreamProcessors.end(); + ++it ) + { + if ( *it == stream ) { + m_StreamProcessors.erase(it); + debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it); + return true; + } + } + return false; //not found +} + +/** + * @brief unregister a handler from the manager + * @note called without the lock held. + */ +void IsoHandlerManager::pruneHandlers() { + debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); + IsoHandlerVector toUnregister; + + // find all handlers that are not in use + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if(!((*it)->inUse())) { + debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it); + toUnregister.push_back(*it); + } + } + // delete them + for ( IsoHandlerVectorIterator it = toUnregister.begin(); + it != toUnregister.end(); + ++it ) + { + unregisterHandler(*it); + + debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it); + + // Now the handler's been unregistered it won't be reused + // again. Therefore it really needs to be formally deleted + // to free up the raw1394 handle. Otherwise things fall + // apart after several xrun recoveries as the system runs + // out of resources to support all the disused but still + // allocated raw1394 handles. At least this is the current + // theory as to why we end up with "memory allocation" + // failures after several Xrun recoveries. + delete *it; + } +} + +int +IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) { + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if((*it)->isStreamRegistered(stream)) { + return (*it)->getIrqInterval(); + } + } + debugError("Stream %p has no attached handler\n", stream); + return 0; +} + +IsoHandler * +IsoHandlerManager::getHandlerForStream(Streaming::StreamProcessor *stream) { + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if((*it)->isStreamRegistered(stream)) { + return (*it); + } + } + debugError("Stream %p has no attached handler\n", stream); + return NULL; +} + +bool +IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) { + return startHandlerForStream(stream, -1); +} + +bool +IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) { + // check state + if(m_State != E_Running) { + debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State)); + return false; + } + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if((*it)->isStreamRegistered(stream)) { + debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream); + if(!(*it)->requestEnable(cycle)) { + debugOutput( DEBUG_LEVEL_VERBOSE, " could not request enable for handler %p)\n",*it); + return false; + } + + if((*it)->getType() == IsoHandler::eHT_Transmit) { + m_IsoTaskTransmit->requestShadowMapUpdate(); + } else { + m_IsoTaskReceive->requestShadowMapUpdate(); + } + + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " requested enable for handler %p\n", *it); + return true; + } + } + debugError("Stream %p has no attached handler\n", stream); + return false; +} + +bool +IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) { + // check state + if(m_State != E_Running) { + debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State)); + return false; + } + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + if((*it)->isStreamRegistered(stream)) { + debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream); + if(!(*it)->requestDisable()) { + debugOutput( DEBUG_LEVEL_VERBOSE, " could not request disable for handler %p\n",*it); + return false; + } + + if((*it)->getType() == IsoHandler::eHT_Transmit) { + m_IsoTaskTransmit->requestShadowMapUpdate(); + } else { + m_IsoTaskReceive->requestShadowMapUpdate(); + } + + debugOutput(DEBUG_LEVEL_VERBOSE, " requested disable for handler %p\n", *it); + return true; + } + } + debugError("Stream %p has no attached handler\n", stream); + return false; +} + +bool IsoHandlerManager::stopHandlers() { + debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); + + // check state + if(m_State != E_Running) { + debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State)); + return false; + } + + bool retval=true; + + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it); + + if(!(*it)->requestDisable()) { + debugOutput( DEBUG_LEVEL_VERBOSE, " could not request disable for handler %p\n",*it); + return false; + } + + if((*it)->getType() == IsoHandler::eHT_Transmit) { + m_IsoTaskTransmit->requestShadowMapUpdate(); + } else { + m_IsoTaskReceive->requestShadowMapUpdate(); + } + + debugOutput(DEBUG_LEVEL_VERBOSE, " requested disable for handler %p\n", *it); + } + + if (retval) { + m_State=E_Prepared; + } else { + m_State=E_Error; + } + return retval; +} + +bool IsoHandlerManager::reset() { + debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); + // check state + if(m_State == E_Error) { + debugFatal("Resetting from error condition not yet supported...\n"); + return false; + } + // if not in an error condition, reset means stop the handlers + return stopHandlers(); +} + +void IsoHandlerManager::setVerboseLevel(int i) { + setDebugLevel(i); + // propagate the debug level + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + (*it)->setVerboseLevel(i); + } + if(m_IsoThreadTransmit) m_IsoThreadTransmit->setVerboseLevel(i); + if(m_IsoTaskTransmit) m_IsoTaskTransmit->setVerboseLevel(i); + if(m_IsoThreadReceive) m_IsoThreadReceive->setVerboseLevel(i); + if(m_IsoTaskReceive) m_IsoTaskReceive->setVerboseLevel(i); + setDebugLevel(i); + debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", i ); +} + +void IsoHandlerManager::dumpInfo() { + #ifdef DEBUG + unsigned int i=0; + debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n"); + debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State); + + for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin(); + it != m_IsoHandlers.end(); + ++it ) + { + debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it); + (*it)->dumpInfo(); + } + #endif +} + +const char * +IsoHandlerManager::eHSToString(enum eHandlerStates s) { + switch (s) { + default: return "Invalid"; + case E_Created: return "Created"; + case E_Prepared: return "Prepared"; + case E_Running: return "Running"; + case E_Error: return "Error"; + } +} Index: /tags/2.0-rc2/src/libieee1394/configrom.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/configrom.h (revision 1292) +++ /tags/2.0-rc2/src/libieee1394/configrom.h (revision 1292) @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2005-2008 by Daniel Wagner + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#ifndef CONFIGROM_H +#define CONFIGROM_H + +#include "fbtypes.h" +#include "csr1212.h" + +#include "libutil/serialize.h" +#include "debugmodule/debugmodule.h" + +#include "libcontrol/Element.h" + +#include + +class Ieee1394Service; + +class ConfigRom + : public Control::Element +{ + public: + ConfigRom( Ieee1394Service& ieee1394service, fb_nodeid_t nodeId ); + virtual ~ConfigRom() {}; + + Ieee1394Service& get1394Service(); + + bool initialize(); + + bool operator == ( const ConfigRom& rhs ); + + const fb_nodeid_t getNodeId() const; + const fb_octlet_t getGuid() const; + const std::string getGuidString() const; + const std::string getModelName() const; + const std::string getVendorName() const; + + const unsigned int getModelId() const; + // FIXME: isn't this the same as getNodeVendorId? + const unsigned int getVendorId() const; + const unsigned int getUnitSpecifierId() const; + const unsigned int getUnitVersion() const; + + bool isIsoResourseManager() const + { return m_isIsoResourceManager; } + bool isCycleMasterCapable() const + { return m_isCycleMasterCapable; } + bool isSupportsIsoOperations() const + { return m_isSupportIsoOperations; } + bool isBusManagerCapable() const + { return m_isBusManagerCapable; } + fb_byte_t getCycleClockAccurancy() const + { return m_cycleClkAcc; } + fb_byte_t getMaxRec() const + { return m_maxRec; } + unsigned short getAsyMaxPayload() const; + + fb_quadlet_t getNodeVendorId() const + { return m_nodeVendorId; } + + bool updatedNodeId(); + bool setNodeId( fb_nodeid_t nodeId ); + + /** + * @brief Compares the GUID of two ConfigRom's + * + * This function compares the GUID of two ConfigRom objects and returns true + * if the GUID of @ref a is larger than the GUID of @ref b . This is intended + * to be used with the STL sort() algorithm. + * + * Note that GUID's are converted to integers for this. + * + * @param a pointer to first ConfigRom + * @param b pointer to second ConfigRom + * + * @returns true if the GUID of @ref a is larger than the GUID of @ref b . + */ + static bool compareGUID( const ConfigRom& a, const ConfigRom& b ); + + bool serialize( std::string path, Util::IOSerialize& ser ); + static ConfigRom* deserialize( std::string path, + Util::IODeserialize& deser, + Ieee1394Service& ieee1394Service ); + + void printConfigRomDebug() const; + void printConfigRom() const; + void setVerboseLevel(int level) { + setDebugLevel(level); + Element::setVerboseLevel(level); + } + + bool isPresentOnBus() { + return m_nodeId != INVALID_NODE_ID; + }; + protected: + void processUnitDirectory( struct csr1212_csr* csr, + struct csr1212_keyval* ud_kv, + unsigned int* id ); + + void processRootDirectory( struct csr1212_csr* csr ); + + Ieee1394Service& m_1394Service; + fb_nodeid_t m_nodeId; + bool m_avcDevice; + fb_octlet_t m_guid; + std::string m_vendorName; + std::string m_modelName; + unsigned int m_vendorId; + unsigned int m_modelId; + unsigned int m_unit_specifier_id; + unsigned int m_unit_version; + bool m_isIsoResourceManager; + bool m_isCycleMasterCapable; + bool m_isSupportIsoOperations; + bool m_isBusManagerCapable; + fb_byte_t m_cycleClkAcc; + fb_byte_t m_maxRec; + fb_quadlet_t m_nodeVendorId; + fb_byte_t m_chipIdHi; + fb_quadlet_t m_chipIdLow; + + /* only used during parsing */ + struct csr1212_keyval* m_vendorNameKv; + struct csr1212_keyval* m_modelNameKv; + struct csr1212_csr* m_csr; + +private: + ConfigRom( const ConfigRom& ); // do not allow copy ctor + ConfigRom(); // ctor for deserialition + + DECLARE_DEBUG_MODULE; +}; + +#endif /* CONFIGROM_H */ Index: /tags/2.0-rc2/src/libieee1394/IsoHandlerManager.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/IsoHandlerManager.h (revision 1526) +++ /tags/2.0-rc2/src/libieee1394/IsoHandlerManager.h (revision 1526) @@ -0,0 +1,246 @@ +/* + * 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 . + * + */ + +#ifndef __FFADO_ISOHANDLERMANAGER__ +#define __FFADO_ISOHANDLERMANAGER__ + +#include "config.h" +#include "debugmodule/debugmodule.h" + +#include "libutil/Thread.h" + +#include "IsoHandler.h" + +#include +#include +#include +#include + +class Ieee1394Service; +//class IsoHandler; +//enum IsoHandler::EHandlerType; + +namespace Streaming { + class StreamProcessor; + typedef std::vector StreamProcessorVector; + typedef std::vector::iterator StreamProcessorVectorIterator; +} + +typedef std::vector IsoHandlerVector; +typedef std::vector::iterator IsoHandlerVectorIterator; + +class IsoHandlerManager; + +// threads that will handle the packet framing +// one thread per direction, as a compromise for one per +// channel and one for all +class IsoTask : public Util::RunnableInterface +{ + friend class IsoHandlerManager; + public: + IsoTask(IsoHandlerManager& manager, enum IsoHandler::EHandlerType); + virtual ~IsoTask(); + + public: + bool Init(); + bool Execute(); + + /** + * @brief requests the thread to sync it's stream map with the manager + */ + void requestShadowMapUpdate(); + enum eActivityResult { + eAR_Activity, + eAR_Timeout, + eAR_Interrupted, + eAR_Error + }; + + /** + * @brief signals that something happened in one of the clients of this task + */ + void signalActivity(); + /** + * @brief wait until something happened in one of the clients of this task + */ + enum eActivityResult waitForActivity(); + + /** + * @brief This should be called when a busreset has happened. + */ + bool handleBusReset(); + + void setVerboseLevel(int i); + protected: + IsoHandlerManager& m_manager; + + // the event request structure + int32_t request_update; + + // static allocation due to RT constraints + // this is the map used by the actual thread + // it is a shadow of the m_StreamProcessors vector + struct pollfd m_poll_fds_shadow[ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT]; + IsoHandler * m_IsoHandler_map_shadow[ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT]; + unsigned int m_poll_nfds_shadow; + IsoHandler * m_SyncIsoHandler; + + // updates the streams map + void updateShadowMapHelper(); + +#ifdef DEBUG + uint64_t m_last_loop_entry; + int m_successive_short_loops; +#endif + + enum IsoHandler::EHandlerType m_handlerType; + bool m_running; + bool m_in_busreset; + + // activity signaling + sem_t m_activity_semaphore; + long long int m_activity_wait_timeout_nsec; + + // debug stuff + DECLARE_DEBUG_MODULE; +}; + +/*! +\brief The ISO Handler management class + + This class manages the use of ISO handlers by ISO streams. + You can register an Streaming::StreamProcessor with an IsoHandlerManager. This + manager will assign an IsoHandler to the stream. If nescessary + the manager allocates a new handler. If there is already a handler + that can handle the Streaming::StreamProcessor (e.g. in case of multichannel receive), + it can be assigned. + +*/ + +class IsoHandlerManager +{ + friend class IsoTask; + + public: + + IsoHandlerManager(Ieee1394Service& service); + IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio); + virtual ~IsoHandlerManager(); + + bool setThreadParameters(bool rt, int priority); + + void setVerboseLevel(int l); ///< set the verbose level + + void dumpInfo(); ///< print some information about the manager to stdout/stderr + + bool registerStream(Streaming::StreamProcessor *); ///< register an iso stream with the manager + bool unregisterStream(Streaming::StreamProcessor *); ///< unregister an iso stream from the manager + + bool startHandlers(); ///< start the managed ISO handlers + bool startHandlers(int cycle); ///< start the managed ISO handlers + bool stopHandlers(); ///< stop the managed ISO handlers + + bool reset(); ///< reset the ISO manager and all streams + bool init(); + + /** + * @brief signals that something happened in one of the clients + */ + void signalActivityTransmit(); + void signalActivityReceive(); + + ///> disables the handler attached to the stream + bool stopHandlerForStream(Streaming::StreamProcessor *); + ///> starts the handler attached to the specific stream + bool startHandlerForStream(Streaming::StreamProcessor *); + ///> starts the handler attached to the specific stream on a specific cycle + bool startHandlerForStream(Streaming::StreamProcessor *, int cycle); + + /** + * returns the latency of a wake-up for this stream. + * The latency is the time it takes for a packet is delivered to the + * stream after it has been received (was on the wire). + * expressed in cycles + */ + int getPacketLatencyForStream(Streaming::StreamProcessor *); + + IsoHandler * getHandlerForStream(Streaming::StreamProcessor *stream); + + Ieee1394Service& get1394Service() {return m_service;}; + + void requestShadowMapUpdate(); + + /** + * This should be called when a busreset has happened. + */ + bool handleBusReset(); + + // the state machine + private: + enum eHandlerStates { + E_Created, + E_Prepared, + E_Running, + E_Error + }; + + enum eHandlerStates m_State; + const char *eHSToString(enum eHandlerStates); + + private: + Ieee1394Service& m_service; + // note: there is a disctinction between streams and handlers + // because one handler can serve multiple streams (in case of + // multichannel receive) + + // only streams are allowed to be registered externally. + // we allocate a handler if we need one, otherwise the stream + // is assigned to another handler + + // the collection of handlers + IsoHandlerVector m_IsoHandlers; + + bool registerHandler(IsoHandler *); + bool unregisterHandler(IsoHandler *); + void pruneHandlers(); + + // the collection of streams + Streaming::StreamProcessorVector m_StreamProcessors; + + // handler thread/task + bool m_realtime; + int m_priority; + Util::Thread * m_IsoThreadTransmit; + IsoTask * m_IsoTaskTransmit; + Util::Thread * m_IsoThreadReceive; + IsoTask * m_IsoTaskReceive; + + // debug stuff + DECLARE_DEBUG_MODULE; + +}; + +#endif /* __FFADO_ISOHANDLERMANAGER__ */ + + + Index: /tags/2.0-rc2/src/libieee1394/IsoHandler.cpp =================================================================== --- /tags/2.0-rc2/src/libieee1394/IsoHandler.cpp (revision 1561) +++ /tags/2.0-rc2/src/libieee1394/IsoHandler.cpp (revision 1561) @@ -0,0 +1,777 @@ +/* + * 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 . + * + */ + +#include "config.h" + +#include "IsoHandler.h" +#include "ieee1394service.h" +#include "IsoHandlerManager.h" + +#include "cycletimer.h" + +#include "libstreaming/generic/StreamProcessor.h" +#include "libutil/PosixThread.h" + +#include +#include "libutil/ByteSwap.h" +#include +#include +#include + +#include +using namespace std; +using namespace Streaming; + +IMPL_DEBUG_MODULE( IsoHandler, IsoHandler, DEBUG_LEVEL_NORMAL ); + +/* the C callbacks */ +enum raw1394_iso_disposition +IsoHandler::iso_transmit_handler(raw1394handle_t handle, + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped1) { + + IsoHandler *xmitHandler = static_cast(raw1394_get_userdata(handle)); + assert(xmitHandler); + unsigned int skipped = (dropped1 & 0xFFFF0000) >> 16; + unsigned int dropped = dropped1 & 0xFFFF; + return xmitHandler->getPacket(data, length, tag, sy, cycle, dropped, skipped); +} + +enum raw1394_iso_disposition +IsoHandler::iso_receive_handler(raw1394handle_t handle, unsigned char *data, + unsigned int length, unsigned char channel, + unsigned char tag, unsigned char sy, unsigned int cycle, + unsigned int dropped) { + + IsoHandler *recvHandler = static_cast(raw1394_get_userdata(handle)); + assert(recvHandler); + + return recvHandler->putPacket(data, length, channel, tag, sy, cycle, dropped); +} + +IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t) + : m_manager( manager ) + , m_type ( t ) + , m_handle( NULL ) + , m_buf_packets( 400 ) + , m_max_packet_size( 1024 ) + , m_irq_interval( -1 ) + , m_last_cycle( -1 ) + , m_last_now( 0xFFFFFFFF ) + , m_last_packet_handled_at( 0xFFFFFFFF ) + , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) + , m_Client( 0 ) + , m_speed( RAW1394_ISO_SPEED_400 ) + , m_prebuffers( 0 ) + , m_dont_exit_iterate_loop( true ) + , m_State( eHS_Stopped ) + , m_NextState( eHS_Stopped ) + , m_switch_on_cycle(0) +#ifdef DEBUG + , m_packets ( 0 ) + , m_dropped( 0 ) + , m_skipped( 0 ) + , m_min_ahead( 7999 ) +#endif +{ +} + +IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, + unsigned int buf_packets, unsigned int max_packet_size, int irq) + : m_manager( manager ) + , m_type ( t ) + , m_handle( NULL ) + , m_buf_packets( buf_packets ) + , m_max_packet_size( max_packet_size ) + , m_irq_interval( irq ) + , m_last_cycle( -1 ) + , m_last_now( 0xFFFFFFFF ) + , m_last_packet_handled_at( 0xFFFFFFFF ) + , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) + , m_Client( 0 ) + , m_speed( RAW1394_ISO_SPEED_400 ) + , m_prebuffers( 0 ) + , m_State( eHS_Stopped ) + , m_NextState( eHS_Stopped ) + , m_switch_on_cycle(0) +#ifdef DEBUG + , m_packets ( 0 ) + , m_dropped( 0 ) + , m_skipped( 0 ) + , m_min_ahead( 7999 ) +#endif +{ +} + +IsoHandler::IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, unsigned int buf_packets, + unsigned int max_packet_size, int irq, + enum raw1394_iso_speed speed) + : m_manager( manager ) + , m_type ( t ) + , m_handle( NULL ) + , m_buf_packets( buf_packets ) + , m_max_packet_size( max_packet_size ) + , m_irq_interval( irq ) + , m_last_cycle( -1 ) + , m_last_now( 0xFFFFFFFF ) + , m_last_packet_handled_at( 0xFFFFFFFF ) + , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) + , m_Client( 0 ) + , m_speed( speed ) + , m_prebuffers( 0 ) + , m_State( eHS_Stopped ) + , m_NextState( eHS_Stopped ) + , m_switch_on_cycle(0) +#ifdef DEBUG + , m_packets( 0 ) + , m_dropped( 0 ) + , m_skipped( 0 ) + , m_min_ahead( 7999 ) +#endif +{ +} + +IsoHandler::~IsoHandler() { +// Don't call until libraw1394's raw1394_new_handle() function has been +// fixed to correctly initialise the iso_packet_infos field. Bug is +// confirmed present in libraw1394 1.2.1. In any case, +// raw1394_destroy_handle() will do any iso system shutdown required. +// raw1394_iso_shutdown(m_handle); + if(m_handle) { + if (m_State == eHS_Running) { + debugError("BUG: Handler still running!\n"); + disable(); + } + } +} + +bool +IsoHandler::canIterateClient() +{ + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "checking...\n"); + if(m_Client) { + bool result; + + if (m_type == eHT_Receive) { + result = m_Client->canProducePacket(); + } else { + result = m_Client->canConsumePacket(); + } + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " returns %d\n", result); + return result && (m_State != eHS_Error); + } else { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, " no client\n"); + } + return false; +} + +bool +IsoHandler::iterate() { + return iterate(m_manager.get1394Service().getCycleTimer()); +} + +bool +IsoHandler::iterate(uint32_t cycle_timer_now) { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) Iterating ISO handler at %08X...\n", + this, getTypeString(), cycle_timer_now); + m_last_now = cycle_timer_now; + if(m_State == eHS_Running) { + assert(m_handle); + + #if ISOHANDLER_FLUSH_BEFORE_ITERATE + // this flushes all packets received since the poll() returned + // from kernel to userspace such that they are processed by this + // iterate. Doing so might result in lower latency capability + // and/or better reliability + if(m_type == eHT_Receive) { + raw1394_iso_recv_flush(m_handle); + } + #endif + + if(raw1394_loop_iterate(m_handle)) { + debugError( "IsoHandler (%p): Failed to iterate handler: %s\n", + this, strerror(errno)); + return false; + } + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "(%p, %s) done interating ISO handler...\n", + this, getTypeString()); + return true; + } else { + debugOutput(DEBUG_LEVEL_VERBOSE, "(%p, %s) Not iterating a non-running handler...\n", + this, getTypeString()); + return false; + } +} + +/** + * Bus reset handler + * + * @return ? + */ + +bool +IsoHandler::handleBusReset() +{ + debugOutput( DEBUG_LEVEL_NORMAL, "bus reset...\n"); + m_last_packet_handled_at = 0xFFFFFFFF; + + #define CSR_CYCLE_TIME 0x200 + #define CSR_REGISTER_BASE 0xfffff0000000ULL + // do a simple read on ourself in order to update the internal structures + // this avoids read failures after a bus reset + quadlet_t buf=0; + raw1394_read(m_handle, raw1394_get_local_id(m_handle), + CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); + + return m_Client->handleBusReset(); +} + +/** + * Call this if you find out that this handler has died for some + * external reason. + */ +void +IsoHandler::notifyOfDeath() +{ + m_State = eHS_Error; + m_NextState = eHS_Error; + + // notify the client of the fact that we have died + m_Client->handlerDied(); + + // wake ourselves up + if(m_handle) raw1394_wake_up(m_handle); +} + +void IsoHandler::dumpInfo() +{ + int channel=-1; + if (m_Client) channel=m_Client->getChannel(); + + debugOutputShort( DEBUG_LEVEL_NORMAL, " Handler type................: %s\n", + getTypeString()); + debugOutputShort( DEBUG_LEVEL_NORMAL, " Port, Channel...............: %2d, %2d\n", + m_manager.get1394Service().getPort(), channel); + debugOutputShort( DEBUG_LEVEL_NORMAL, " Buffer, MaxPacketSize, IRQ..: %4d, %4d, %4d\n", + m_buf_packets, m_max_packet_size, m_irq_interval); + if (this->getType() == eHT_Transmit) { + debugOutputShort( DEBUG_LEVEL_NORMAL, " Speed, PreBuffers...........: %2d, %2d\n", + m_speed, m_prebuffers); + #ifdef DEBUG + debugOutputShort( DEBUG_LEVEL_NORMAL, " Min ISOXMT bufferfill : %04d\n", m_min_ahead); + #endif + } + #ifdef DEBUG + debugOutputShort( DEBUG_LEVEL_NORMAL, " Last cycle, dropped.........: %4d, %4u, %4u\n", + m_last_cycle, m_dropped, m_skipped); + #endif + +} + +void IsoHandler::setVerboseLevel(int l) +{ + setDebugLevel(l); + debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l ); +} + +bool IsoHandler::registerStream(StreamProcessor *stream) +{ + assert(stream); + debugOutput( DEBUG_LEVEL_VERBOSE, "registering stream (%p)\n", stream); + + if (m_Client) { + debugFatal( "Generic IsoHandlers can have only one client\n"); + return false; + } + m_Client=stream; + return true; +} + +bool IsoHandler::unregisterStream(StreamProcessor *stream) +{ + assert(stream); + debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering stream (%p)\n", stream); + + if(stream != m_Client) { + debugFatal( "no client registered\n"); + return false; + } + m_Client=0; + return true; +} + +// ISO packet interface +enum raw1394_iso_disposition IsoHandler::putPacket( + unsigned char *data, unsigned int length, + unsigned char channel, unsigned char tag, unsigned char sy, + unsigned int cycle, unsigned int dropped) { + // keep track of dropped cycles + int dropped_cycles = 0; + if (m_last_cycle != (int)cycle && m_last_cycle != -1) { + dropped_cycles = diffCycles(cycle, m_last_cycle) - 1; + #ifdef DEBUG + if (dropped_cycles < 0) { + debugWarning("(%p) dropped < 1 (%d), cycle: %d, last_cycle: %d, dropped: %d\n", + this, dropped_cycles, cycle, m_last_cycle, dropped); + } + if (dropped_cycles > 0) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) dropped %d packets on cycle %u, 'dropped'=%u, cycle=%d, m_last_cycle=%d\n", + this, dropped_cycles, cycle, dropped, cycle, m_last_cycle); + m_dropped += dropped_cycles; + } + #endif + } + m_last_cycle = cycle; + + // the m_last_now value is set when the iterate() function is called. + uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now); + + // two cases can occur: + // (1) this packet has been received before iterate() was called (normal case). + // (2) this packet has been received after iterate() was called. + // happens when the kernel flushes more packets while we are already processing. + // + // In case (1) now_cycles is a small number of cycles larger than cycle. In + // case (2) now_cycles is a small number of cycles smaller than cycle. + // hence abs(diffCycles(now_cycles, cycles)) has to be 'small' + + // we can calculate the time of arrival for this packet as + // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE + // in its properly wrapped version + int64_t diff_cycles = diffCycles(cycle, now_cycles); + int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now); + tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE; + uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp); + uint32_t pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks); + #ifdef DEBUG + if( (now_cycles < cycle) + && diffCycles(now_cycles, cycle) < 0 + // ignore this on dropped cycles, since it's normal + // that now is ahead on the received packets (as we miss packets) + && dropped_cycles == 0) + { + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Special non-unwrapping happened\n"); + } + #endif + + #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION + // add a seconds field + uint32_t now = m_manager.get1394Service().getCycleTimer(); + uint32_t now_secs_ref = CYCLE_TIMER_GET_SECS(now); + // causality results in the fact that 'now' is always after 'cycle' + // or at best, equal (if this handler was called within 125us after + // the packet was on the wire). + if(CYCLE_TIMER_GET_CYCLES(now) < cycle) { + // the cycle field has wrapped, substract one second + if(now_secs_ref == 0) { + now_secs_ref = 127; + } else { + now_secs_ref -= 1; + } + } + uint32_t pkt_ctr_ref = cycle << 12; + pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25; + + if((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) { + debugWarning("reconstructed CTR counter discrepancy\n"); + debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld, %ld, %lld\n", + cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_SECS(m_last_now), tmp); + debugWarning(" diffcy = %ld \n", diff_cycles); + } + #endif + m_last_packet_handled_at = pkt_ctr; + + // leave the offset field (for now?) + + debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, + "received packet: length=%d, channel=%d, cycle=%d, at %08X\n", + length, channel, cycle, pkt_ctr); + m_packets++; + #ifdef DEBUG + if (length > m_max_packet_size) { + debugWarning("(%p, %s) packet too large: len=%u max=%u\n", + this, getTypeString(), length, m_max_packet_size); + } + if(m_last_cycle == -1) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %u)\n", getTypeString(), this, cycle); + } + #endif + + // iterate the client if required + if(m_Client) { + enum raw1394_iso_disposition retval = m_Client->putPacket(data, length, channel, tag, sy, pkt_ctr, dropped_cycles); + if (retval == RAW1394_ISO_OK) { + if (m_dont_exit_iterate_loop) { + return RAW1394_ISO_OK; + } else { + m_dont_exit_iterate_loop = true; + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) loop exit requested\n", + this); + return RAW1394_ISO_DEFER; + } + } else { + return retval; + } + } + + return RAW1394_ISO_OK; +} + +enum raw1394_iso_disposition +IsoHandler::getPacket(unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped, unsigned int skipped) { + + uint32_t pkt_ctr; + if (cycle < 0) { + // mark invalid + pkt_ctr = 0xFFFFFFFF; + } else { + // the m_last_now value is set when the iterate() function is called. + uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now); + + // two cases can occur: + // (1) this packet has been received before iterate() was called (normal case). + // (2) this packet has been received after iterate() was called. + // happens when the kernel flushes more packets while we are already processing. + // + // In case (1) now_cycles is a small number of cycles larger than cycle. In + // case (2) now_cycles is a small number of cycles smaller than cycle. + // hence abs(diffCycles(now_cycles, cycles)) has to be 'small' + + // we can calculate the time of arrival for this packet as + // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE + // in its properly wrapped version + int64_t diff_cycles = diffCycles(cycle, now_cycles); + int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now); + tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE; + uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp); + pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks); + + #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION + // add a seconds field + uint32_t now = m_manager.get1394Service().getCycleTimer(); + uint32_t now_secs_ref = CYCLE_TIMER_GET_SECS(now); + // causality results in the fact that 'now' is always after 'cycle' + if(CYCLE_TIMER_GET_CYCLES(now) > (unsigned int)cycle) { + // the cycle field has wrapped, add one second + now_secs_ref += 1; + // no need for this: + if(now_secs_ref == 128) { + now_secs_ref = 0; + } + } + uint32_t pkt_ctr_ref = cycle << 12; + pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25; + + if(((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) && (m_packets > m_buf_packets)) { + debugWarning("reconstructed CTR counter discrepancy\n"); + debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld, %ld, %lld\n", + cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_SECS(m_last_now), tmp); + debugWarning(" diffcy = %ld \n", diff_cycles); + } + #endif + } + if (m_packets < m_buf_packets) { // these are still prebuffer packets + m_last_packet_handled_at = 0xFFFFFFFF; + } else { + m_last_packet_handled_at = pkt_ctr; + } + debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, + "sending packet: length=%d, cycle=%d, at %08X\n", + *length, cycle, pkt_ctr); + + m_packets++; + + #ifdef DEBUG + if(m_last_cycle == -1) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Handler for %s SP %p is alive (cycle = %d)\n", getTypeString(), this, cycle); + } + #endif + + // keep track of dropped cycles + int dropped_cycles = 0; + if (m_last_cycle != cycle && m_last_cycle != -1) { + dropped_cycles = diffCycles(cycle, m_last_cycle) - 1; + // correct for skipped packets + // since those are not dropped, but only delayed + dropped_cycles -= skipped; + + #ifdef DEBUG + if(skipped) { + debugOutput(DEBUG_LEVEL_VERY_VERBOSE, + "(%p) skipped %d cycles, cycle: %d, last_cycle: %d, dropped: %d\n", + this, skipped, cycle, m_last_cycle, dropped); + m_skipped += skipped; + } + if (dropped_cycles < 0) { + debugWarning("(%p) dropped < 1 (%d), cycle: %d, last_cycle: %d, dropped: %d, skipped: %d\n", + this, dropped_cycles, cycle, m_last_cycle, dropped, skipped); + } + if (dropped_cycles > 0) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) dropped %d packets on cycle %u (last_cycle=%u, dropped=%d, skipped: %d)\n", + this, dropped_cycles, cycle, m_last_cycle, dropped, skipped); + m_dropped += dropped_cycles - skipped; + } + #endif + } + if (cycle >= 0) { + m_last_cycle = cycle; + + #ifdef DEBUG +/* int ahead = diffCycles(cycle, now_cycles); + if (ahead < m_min_ahead) m_min_ahead = ahead; +*/ + #endif + } + + #ifdef DEBUG + if (dropped > 0) { + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) OHCI issue on cycle %u (dropped_cycles=%d, last_cycle=%u, dropped=%d, skipped: %d)\n", + this, cycle, dropped_cycles, m_last_cycle, dropped, skipped); + } + #endif + + if(m_Client) { + enum raw1394_iso_disposition retval; + retval = m_Client->getPacket(data, length, tag, sy, pkt_ctr, dropped_cycles, skipped, m_max_packet_size); + #ifdef DEBUG + if (*length > m_max_packet_size) { + debugWarning("(%p, %s) packet too large: len=%u max=%u\n", + this, getTypeString(), *length, m_max_packet_size); + } + #endif + if (retval == RAW1394_ISO_OK) { + if (m_dont_exit_iterate_loop) { + return RAW1394_ISO_OK; + } else { + m_dont_exit_iterate_loop = true; + debugOutput(DEBUG_LEVEL_VERBOSE, + "(%p) loop exit requested\n", + this); + return RAW1394_ISO_DEFER; + } + } else { + return retval; + } + } + + *tag = 0; + *sy = 0; + *length = 0; + return RAW1394_ISO_OK; +} + +bool +IsoHandler::enable(int cycle) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle); + + // check the state + if(m_State != eHS_Stopped) { + debugError("Incorrect state, expected eHS_Stopped, got %d\n",(int)m_State); + return false; + } + + assert(m_handle == NULL); + + // create a handle for the ISO traffic + m_handle = raw1394_new_handle_on_port( m_manager.get1394Service().getPort() ); + if ( !m_handle ) { + if ( !errno ) { + debugError("libraw1394 not compatible\n"); + } else { + debugError("Could not get 1394 handle: %s\n", strerror(errno) ); + debugError("Are ieee1394 and raw1394 drivers loaded?\n"); + } + return false; + } + raw1394_set_userdata(m_handle, static_cast(this)); + + // prepare the handler, allocate the resources + debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso handler (%p, client=%p)\n", this, m_Client); + dumpInfo(); + if (getType() == eHT_Receive) { + if(raw1394_iso_recv_init(m_handle, + iso_receive_handler, + m_buf_packets, + m_max_packet_size, + m_Client->getChannel(), + m_receive_mode, + m_irq_interval)) { + debugFatal("Could not do receive initialisation!\n" ); + debugFatal(" %s\n",strerror(errno)); + return false; + } + + if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) { + debugFatal("Could not start receive handler (%s)\n",strerror(errno)); + dumpInfo(); + return false; + } + } else { + if(raw1394_iso_xmit_init(m_handle, + iso_transmit_handler, + m_buf_packets, + m_max_packet_size, + m_Client->getChannel(), + m_speed, + m_irq_interval)) { + debugFatal("Could not do xmit initialisation!\n" ); + return false; + } + + if(raw1394_iso_xmit_start(m_handle, cycle, m_prebuffers)) { + debugFatal("Could not start xmit handler (%s)\n",strerror(errno)); + dumpInfo(); + return false; + } + } + +#ifdef DEBUG + m_min_ahead = 7999; +#endif + + m_packets = 0; + + // indicate that the first iterate() still has to occur. + m_last_now = 0xFFFFFFFF; + m_last_packet_handled_at = 0xFFFFFFFF; + + m_State = eHS_Running; + m_NextState = eHS_Running; + return true; +} + +bool +IsoHandler::disable() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) enter...\n", + this, (m_type==eHT_Receive?"Receive":"Transmit")); + + // check state + if(m_State != eHS_Running) { + debugError("Incorrect state, expected eHS_Running, got %d\n",(int)m_State); + return false; + } + + assert(m_handle != NULL); + + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) wake up handle...\n", + this, (m_type==eHT_Receive?"Receive":"Transmit")); + + // wake up any waiting reads/polls + raw1394_wake_up(m_handle); + + // this is put here to try and avoid the + // Runaway context problem + // don't know if it will help though. +/* if(m_State != eHS_Error) { // if the handler is dead, this might block forever + raw1394_iso_xmit_sync(m_handle); + }*/ + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p, %s) stop...\n", + this, (m_type==eHT_Receive?"Receive":"Transmit")); + // stop iso traffic + raw1394_iso_stop(m_handle); + // deallocate resources + + // Don't call until libraw1394's raw1394_new_handle() function has been + // fixed to correctly initialise the iso_packet_infos field. Bug is + // confirmed present in libraw1394 1.2.1. + raw1394_iso_shutdown(m_handle); + + raw1394_destroy_handle(m_handle); + m_handle = NULL; + + m_State = eHS_Stopped; + m_NextState = eHS_Stopped; + return true; +} + +// functions to request enable or disable at the next opportunity +bool +IsoHandler::requestEnable(int cycle) +{ + if (m_State == eHS_Running) { + debugError("Enable requested on enabled stream\n"); + return false; + } + if (m_State != eHS_Stopped) { + debugError("Enable requested on stream with state: %d\n", m_State); + return false; + } + m_NextState = eHS_Running; + return true; +} + +bool +IsoHandler::requestDisable() +{ + if (m_State == eHS_Stopped) { + debugError("Disable requested on disabled stream\n"); + return false; + } + if (m_State != eHS_Running) { + debugError("Disable requested on stream with state=%d\n", m_State); + return false; + } + m_NextState = eHS_Stopped; + return true; +} + +void +IsoHandler::updateState() +{ + // execute state changes requested + if(m_State != m_NextState) { + debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) handler needs state update from %d => %d\n", this, m_State, m_NextState); + if(m_State == eHS_Stopped && m_NextState == eHS_Running) { + debugOutput(DEBUG_LEVEL_VERBOSE, "handler has to be enabled\n"); + enable(m_switch_on_cycle); + } else if(m_State == eHS_Running && m_NextState == eHS_Stopped) { + debugOutput(DEBUG_LEVEL_VERBOSE, "handler has to be disabled\n"); + disable(); + } else { + debugError("Unknown state transition\n"); + } + } +} + +/** + * @brief convert a EHandlerType to a string + * @param t the type + * @return a char * describing the state + */ +const char * +IsoHandler::eHTToString(enum EHandlerType t) { + switch (t) { + case eHT_Receive: return "Receive"; + case eHT_Transmit: return "Transmit"; + default: return "error: unknown type"; + } +} Index: /tags/2.0-rc2/src/libieee1394/csr1212.c =================================================================== --- /tags/2.0-rc2/src/libieee1394/csr1212.c (revision 864) +++ /tags/2.0-rc2/src/libieee1394/csr1212.c (revision 864) @@ -0,0 +1,1649 @@ +/* + * 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 . + * + */ +/* + * csr1212.c -- IEEE 1212 Control and Status Register support for Linux + * + * Copyright (C) 2003 Francois Retief + * Steve Kinneberg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* TODO List: + * - Verify interface consistency: i.e., public functions that take a size + * parameter expect size to be in bytes. + * - Convenience functions for reading a block of data from a given offset. + */ + +#ifndef __KERNEL__ +#include +#endif + +#include "csr1212.h" + + +/* Permitted key type for each key id */ +#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE) +#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET) +#define __D (1 << CSR1212_KV_TYPE_DIRECTORY) +#define __L (1 << CSR1212_KV_TYPE_LEAF) +static const u_int8_t csr1212_key_id_type_map[0x30] = { + 0, /* Reserved */ + __D | __L, /* Descriptor */ + __I | __D | __L, /* Bus_Dependent_Info */ + __I | __D | __L, /* Vendor */ + __I, /* Hardware_Version */ + 0, 0, /* Reserved */ + __D | __L, /* Module */ + 0, 0, 0, 0, /* Reserved */ + __I, /* Node_Capabilities */ + __L, /* EUI_64 */ + 0, 0, 0, /* Reserved */ + __D, /* Unit */ + __I, /* Specifier_ID */ + __I, /* Version */ + __I | __C | __D | __L, /* Dependent_Info */ + __L, /* Unit_Location */ + 0, /* Reserved */ + __I, /* Model */ + __D, /* Instance */ + __L, /* Keyword */ + __D, /* Feature */ + __L, /* Extended_ROM */ + __I, /* Extended_Key_Specifier_ID */ + __I, /* Extended_Key */ + __I | __C | __D | __L, /* Extended_Data */ + __L, /* Modifiable_Descriptor */ + __I, /* Directory_ID */ + __I, /* Revision */ +}; +#undef __I +#undef __C +#undef __D +#undef __L + + +#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t)) +#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t)) + +static inline void free_keyval(struct csr1212_keyval *kv) +{ + if ((kv->key.type == CSR1212_KV_TYPE_LEAF) && + (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)) + CSR1212_FREE(kv->value.leaf.data); + + CSR1212_FREE(kv); +} + +static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length) +{ + int shift; + u_int32_t data; + u_int16_t sum, crc = 0; + + for (; length; length--) { + data = CSR1212_BE32_TO_CPU(*buffer); + buffer++; + for (shift = 28; shift >= 0; shift -= 4 ) { + sum = ((crc >> 12) ^ (data >> shift)) & 0xf; + crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); + } + crc &= 0xffff; + } + + return CSR1212_CPU_TO_BE16(crc); +} + +#if 0 +/* Microsoft computes the CRC with the bytes in reverse order. Therefore we + * have a special version of the CRC algorithm to account for their buggy + * software. */ +static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length) +{ + int shift; + u_int32_t data; + u_int16_t sum, crc = 0; + + for (; length; length--) { + data = CSR1212_LE32_TO_CPU(*buffer); + buffer++; + for (shift = 28; shift >= 0; shift -= 4 ) { + sum = ((crc >> 12) ^ (data >> shift)) & 0xf; + crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); + } + crc &= 0xffff; + } + + return CSR1212_CPU_TO_BE16(crc); +} +#endif + +static inline struct csr1212_dentry *csr1212_find_keyval(struct csr1212_keyval *dir, + struct csr1212_keyval *kv) +{ + struct csr1212_dentry *pos; + + for (pos = dir->value.directory.dentries_head; + pos != NULL; pos = pos->next) { + if (pos->kv == kv) + return pos; + } + return NULL; +} + + +static inline struct csr1212_keyval *csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, + u_int32_t offset) +{ + struct csr1212_keyval *kv; + + for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) { + if (kv->offset == offset) + return kv; + } + return NULL; +} + + +/* Creation Routines */ +struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, + size_t bus_info_size, void *private_data) +{ + struct csr1212_csr *csr; + + csr = CSR1212_MALLOC(sizeof(*csr)); + if (!csr) + return NULL; + + csr->cache_head = + csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET, + CSR1212_CONFIG_ROM_SPACE_SIZE); + if (!csr->cache_head) { + CSR1212_FREE(csr); + return NULL; + } + + /* The keyval key id is not used for the root node, but a valid key id + * that can be used for a directory needs to be passed to + * csr1212_new_directory(). */ + csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR); + if (!csr->root_kv) { + CSR1212_FREE(csr->cache_head); + CSR1212_FREE(csr); + return NULL; + } + + csr->bus_info_data = csr->cache_head->data; + csr->bus_info_len = bus_info_size; + csr->crc_len = bus_info_size; + csr->ops = ops; + csr->private_data = private_data; + csr->cache_tail = csr->cache_head; + + return csr; +} + + + +void csr1212_init_local_csr(struct csr1212_csr *csr, + const u_int32_t *bus_info_data, int max_rom) +{ + static const int mr_map[] = { 4, 64, 1024, 0 }; + +#ifdef __KERNEL__ + BUG_ON(max_rom & ~0x3); + csr->max_rom = mr_map[max_rom]; +#else + if (max_rom & ~0x3) /* caller supplied invalid argument */ + csr->max_rom = 0; + else + csr->max_rom = mr_map[max_rom]; +#endif + memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len); +} + + +static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key) +{ + struct csr1212_keyval *kv; + + if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0)) + return NULL; + + kv = CSR1212_MALLOC(sizeof(*kv)); + if (!kv) + return NULL; + + kv->key.type = type; + kv->key.id = key; + + kv->associate = NULL; + kv->refcnt = 1; + + kv->next = NULL; + kv->prev = NULL; + kv->offset = 0; + kv->valid = 0; + return kv; +} + +struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value) +{ + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key); + + if (!kv) + return NULL; + + kv->value.immediate = value; + kv->valid = 1; + return kv; +} + +struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t data_len) +{ + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key); + + if (!kv) + return NULL; + + if (data_len > 0) { + kv->value.leaf.data = CSR1212_MALLOC(data_len); + if (!kv->value.leaf.data) { + CSR1212_FREE(kv); + return NULL; + } + + if (data) + memcpy(kv->value.leaf.data, data, data_len); + } else { + kv->value.leaf.data = NULL; + } + + kv->value.leaf.len = bytes_to_quads(data_len); + kv->offset = 0; + kv->valid = 1; + + return kv; +} + +struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset) +{ + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key); + + if (!kv) + return NULL; + + kv->value.csr_offset = csr_offset; + + kv->offset = 0; + kv->valid = 1; + return kv; +} + +struct csr1212_keyval *csr1212_new_directory(u_int8_t key) +{ + struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key); + + if (!kv) + return NULL; + + kv->value.directory.len = 0; + kv->offset = 0; + kv->value.directory.dentries_head = NULL; + kv->value.directory.dentries_tail = NULL; + kv->valid = 1; + return kv; +} + +int csr1212_associate_keyval(struct csr1212_keyval *kv, + struct csr1212_keyval *associate) +{ + if (!kv || !associate) + return CSR1212_EINVAL; + + if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR || + (associate->key.id != CSR1212_KV_ID_DESCRIPTOR && + associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO && + associate->key.id != CSR1212_KV_ID_EXTENDED_KEY && + associate->key.id != CSR1212_KV_ID_EXTENDED_DATA && + associate->key.id < 0x30)) + return CSR1212_EINVAL; + + if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID && + associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) + return CSR1212_EINVAL; + + if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY && + associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) + return CSR1212_EINVAL; + + if (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY && + kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) + return CSR1212_EINVAL; + + if (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA && + kv->key.id != CSR1212_KV_ID_EXTENDED_KEY) + return CSR1212_EINVAL; + + if (kv->associate) + csr1212_release_keyval(kv->associate); + + associate->refcnt++; + kv->associate = associate; + + return CSR1212_SUCCESS; +} + +int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, + struct csr1212_keyval *kv) +{ + struct csr1212_dentry *dentry; + + if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY) + return CSR1212_EINVAL; + + dentry = CSR1212_MALLOC(sizeof(*dentry)); + if (!dentry) + return CSR1212_ENOMEM; + + dentry->kv = kv; + + kv->refcnt++; + + dentry->next = NULL; + dentry->prev = dir->value.directory.dentries_tail; + + if (!dir->value.directory.dentries_head) + dir->value.directory.dentries_head = dentry; + + if (dir->value.directory.dentries_tail) + dir->value.directory.dentries_tail->next = dentry; + dir->value.directory.dentries_tail = dentry; + + return CSR1212_SUCCESS; +} + +struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, u_int32_t key, + u_int32_t value) +{ + struct csr1212_keyval *kvs, *kvk, *kvv; + + kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec); + kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key); + kvv = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_DATA, value); + + if (!kvs || !kvk || !kvv) { + if (kvs) + free_keyval(kvs); + if (kvk) + free_keyval(kvk); + if (kvv) + free_keyval(kvv); + return NULL; + } + + /* Don't keep a local reference to the extended key or value. */ + kvk->refcnt = 0; + kvv->refcnt = 0; + + csr1212_associate_keyval(kvk, kvv); + csr1212_associate_keyval(kvs, kvk); + + return kvs; +} + +struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, u_int32_t key, + const void *data, size_t data_len) +{ + struct csr1212_keyval *kvs, *kvk, *kvv; + + kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec); + kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key); + kvv = csr1212_new_leaf(CSR1212_KV_ID_EXTENDED_DATA, data, data_len); + + if (!kvs || !kvk || !kvv) { + if (kvs) + free_keyval(kvs); + if (kvk) + free_keyval(kvk); + if (kvv) + free_keyval(kvv); + return NULL; + } + + /* Don't keep a local reference to the extended key or value. */ + kvk->refcnt = 0; + kvv->refcnt = 0; + + csr1212_associate_keyval(kvk, kvv); + csr1212_associate_keyval(kvs, kvk); + + return kvs; +} + +struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t specifier_id, + const void *data, size_t data_len) +{ + struct csr1212_keyval *kv; + + kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL, + data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD); + if (!kv) + return NULL; + + CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype); + CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id); + + if (data) { + memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len); + } + + return kv; +} + + +struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth, + u_int16_t cset, + u_int16_t language, + const void *data, + size_t data_len) +{ + struct csr1212_keyval *kv; + char *lstr; + + kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len + + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD); + if (!kv) + return NULL; + + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth); + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset); + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language); + + lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv); + + /* make sure last quadlet is zeroed out */ + *((u_int32_t*)&(lstr[(data_len - 1) & ~0x3])) = 0; + + /* don't copy the NUL terminator */ + memcpy(lstr, data, data_len); + + return kv; +} + +static int csr1212_check_minimal_ascii(const char *s) +{ + static const char minimal_ascii_table[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f, + 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + for (; *s; s++) { + if (minimal_ascii_table[*s & 0x7F] != *s) + return -1; /* failed */ + } + /* String conforms to minimal-ascii, as specified by IEEE 1212, + * par. 7.4 */ + return 0; +} + +struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s) +{ + /* Check if string conform to minimal_ascii format */ + if (csr1212_check_minimal_ascii(s)) + return NULL; + + /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */ + return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s)); +} + +struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version, + u_int8_t palette_depth, + u_int8_t color_space, + u_int16_t language, + u_int16_t hscan, + u_int16_t vscan, + u_int32_t *palette, + u_int32_t *pixels) +{ + static const int pd[4] = { 0, 4, 16, 256 }; + static const int cs[16] = { 4, 2 }; + struct csr1212_keyval *kv; + int palette_size; + int pixel_size = (hscan * vscan + 3) & ~0x3; + + if (!pixels || (!palette && palette_depth) || + (palette_depth & ~0x3) || (color_space & ~0xf)) + return NULL; + + palette_size = pd[palette_depth] * cs[color_space]; + + kv = csr1212_new_descriptor_leaf(1, 0, NULL, + palette_size + pixel_size + + CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD); + if (!kv) + return NULL; + + CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan); + CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan); + + if (palette_size) + memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv), palette, + palette_size); + + memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(kv), pixels, pixel_size); + + return kv; +} + +struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size, + u_int64_t address) +{ + struct csr1212_keyval *kv; + + /* IEEE 1212, par. 7.5.4.3 Modifiable descriptors */ + kv = csr1212_new_leaf(CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR, NULL, sizeof(u_int64_t)); + if(!kv) + return NULL; + + CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, max_size); + CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, address); + CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, address); + + return kv; +} + +static int csr1212_check_keyword(const char *s) +{ + for (; *s; s++) { + + if (('A' <= *s) && (*s <= 'Z')) + continue; + if (('0' <= *s) && (*s <= '9')) + continue; + if (*s == '-') + continue; + + return -1; /* failed */ + } + /* String conforms to keyword, as specified by IEEE 1212, + * par. 7.6.5 */ + return CSR1212_SUCCESS; +} + +struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, const char *strv[]) +{ + struct csr1212_keyval *kv; + char *buffer; + int i, data_len = 0; + + /* Check all keywords to see if they conform to restrictions: + * Only the following characters is allowed ['A'..'Z','0'..'9','-'] + * Each word is zero-terminated. + * Also calculate the total length of the keywords. + */ + for (i = 0; i < strc; i++) { + if (!strv[i] || csr1212_check_keyword(strv[i])) { + return NULL; + } + data_len += strlen(strv[i]) + 1; /* Add zero-termination char. */ + } + + /* IEEE 1212, par. 7.6.5 Keyword leaves */ + kv = csr1212_new_leaf(CSR1212_KV_ID_KEYWORD, NULL, data_len); + if (!kv) + return NULL; + + buffer = (char *)kv->value.leaf.data; + + /* make sure last quadlet is zeroed out */ + *((u_int32_t*)&(buffer[(data_len - 1) & ~0x3])) = 0; + + /* Copy keyword(s) into leaf data buffer */ + for (i = 0; i < strc; i++) { + int len = strlen(strv[i]) + 1; + memcpy(buffer, strv[i], len); + buffer += len; + } + return kv; +} + + +/* Destruction Routines */ + +void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, + struct csr1212_keyval *kv) +{ + struct csr1212_dentry *dentry; + + if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY) + return; + + dentry = csr1212_find_keyval(dir, kv); + + if (!dentry) + return; + + if (dentry->prev) + dentry->prev->next = dentry->next; + if (dentry->next) + dentry->next->prev = dentry->prev; + if (dir->value.directory.dentries_head == dentry) + dir->value.directory.dentries_head = dentry->next; + if (dir->value.directory.dentries_tail == dentry) + dir->value.directory.dentries_tail = dentry->prev; + + CSR1212_FREE(dentry); + + csr1212_release_keyval(kv); +} + + +void csr1212_disassociate_keyval(struct csr1212_keyval *kv) +{ + if (kv->associate) { + csr1212_release_keyval(kv->associate); + } + + kv->associate = NULL; +} + + +/* This function is used to free the memory taken by a keyval. If the given + * keyval is a directory type, then any keyvals contained in that directory + * will be destroyed as well if their respective refcnts are 0. By means of + * list manipulation, this routine will descend a directory structure in a + * non-recursive manner. */ +void _csr1212_destroy_keyval(struct csr1212_keyval *kv) +{ + struct csr1212_keyval *k, *a; + struct csr1212_dentry dentry; + struct csr1212_dentry *head, *tail; + + dentry.kv = kv; + dentry.next = NULL; + dentry.prev = NULL; + + head = &dentry; + tail = head; + + while (head) { + k = head->kv; + + while (k) { + k->refcnt--; + + if (k->refcnt > 0) + break; + + a = k->associate; + + if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) { + /* If the current entry is a directory, then move all + * the entries to the destruction list. */ + if (k->value.directory.dentries_head) { + tail->next = k->value.directory.dentries_head; + k->value.directory.dentries_head->prev = tail; + tail = k->value.directory.dentries_tail; + } + } + free_keyval(k); + k = a; + } + + head = head->next; + if (head) { + if (head->prev && head->prev != &dentry) { + CSR1212_FREE(head->prev); + } + head->prev = NULL; + } else if (tail != &dentry) + CSR1212_FREE(tail); + } +} + + +void csr1212_destroy_csr(struct csr1212_csr *csr) +{ + struct csr1212_csr_rom_cache *c, *oc; + struct csr1212_cache_region *cr, *ocr; + + csr1212_release_keyval(csr->root_kv); + + c = csr->cache_head; + while (c) { + oc = c; + cr = c->filled_head; + while (cr) { + ocr = cr; + cr = cr->next; + CSR1212_FREE(ocr); + } + c = c->next; + CSR1212_FREE(oc); + } + + CSR1212_FREE(csr); +} + + + +/* CSR Image Creation */ + +static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) +{ + struct csr1212_csr_rom_cache *cache; + u_int64_t csr_addr; + + if (!csr || !csr->ops || !csr->ops->allocate_addr_range || + !csr->ops->release_addr || csr->max_rom < 1) + return CSR1212_EINVAL; + + /* ROM size must be a multiple of csr->max_rom */ + romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1); + + csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private_data); + if (csr_addr == ~0ULL) { + return CSR1212_ENOMEM; + } + if (csr_addr < CSR1212_REGISTER_SPACE_BASE) { + /* Invalid address returned from allocate_addr_range(). */ + csr->ops->release_addr(csr_addr, csr->private_data); + return CSR1212_ENOMEM; + } + + cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize); + if (!cache) { + csr->ops->release_addr(csr_addr, csr->private_data); + return CSR1212_ENOMEM; + } + + cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM); + if (!cache->ext_rom) { + csr->ops->release_addr(csr_addr, csr->private_data); + CSR1212_FREE(cache); + return CSR1212_ENOMEM; + } + + if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) { + csr1212_release_keyval(cache->ext_rom); + csr->ops->release_addr(csr_addr, csr->private_data); + CSR1212_FREE(cache); + return CSR1212_ENOMEM; + } + cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE; + cache->ext_rom->value.leaf.len = -1; + cache->ext_rom->value.leaf.data = cache->data; + + /* Add cache to tail of cache list */ + cache->prev = csr->cache_tail; + csr->cache_tail->next = cache; + csr->cache_tail = cache; + return CSR1212_SUCCESS; +} + +static inline void csr1212_remove_cache(struct csr1212_csr *csr, + struct csr1212_csr_rom_cache *cache) +{ + if (csr->cache_head == cache) + csr->cache_head = cache->next; + if (csr->cache_tail == cache) + csr->cache_tail = cache->prev; + + if (cache->prev) + cache->prev->next = cache->next; + if (cache->next) + cache->next->prev = cache->prev; + + if (cache->ext_rom) { + csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom); + csr1212_release_keyval(cache->ext_rom); + } + + CSR1212_FREE(cache); +} + +static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, + struct csr1212_keyval **layout_tail) +{ + struct csr1212_dentry *dentry; + struct csr1212_keyval *dkv; + struct csr1212_keyval *last_extkey_spec = NULL; + struct csr1212_keyval *last_extkey = NULL; + int num_entries = 0; + + for (dentry = dir->value.directory.dentries_head; dentry; + dentry = dentry->next) { + for (dkv = dentry->kv; dkv; dkv = dkv->associate) { + /* Special Case: Extended Key Specifier_ID */ + if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { + if (last_extkey_spec == NULL) { + last_extkey_spec = dkv; + } else if (dkv->value.immediate != last_extkey_spec->value.immediate) { + last_extkey_spec = dkv; + } else { + continue; + } + /* Special Case: Extended Key */ + } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) { + if (last_extkey == NULL) { + last_extkey = dkv; + } else if (dkv->value.immediate != last_extkey->value.immediate) { + last_extkey = dkv; + } else { + continue; + } + } + + num_entries += 1; + + switch(dkv->key.type) { + default: + case CSR1212_KV_TYPE_IMMEDIATE: + case CSR1212_KV_TYPE_CSR_OFFSET: + break; + case CSR1212_KV_TYPE_LEAF: + case CSR1212_KV_TYPE_DIRECTORY: + /* Remove from list */ + if (dkv->prev && (dkv->prev->next == dkv)) + dkv->prev->next = dkv->next; + if (dkv->next && (dkv->next->prev == dkv)) + dkv->next->prev = dkv->prev; + //if (dkv == *layout_tail) + // *layout_tail = dkv->prev; + + /* Special case: Extended ROM leafs */ + if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { + dkv->value.leaf.len = -1; + /* Don't add Extended ROM leafs in the layout list, + * they are handled differently. */ + break; + } + + /* Add to tail of list */ + dkv->next = NULL; + dkv->prev = *layout_tail; + (*layout_tail)->next = dkv; + *layout_tail = dkv; + break; + } + } + } + return num_entries; +} + +size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) +{ + struct csr1212_keyval *ltail = kv; + size_t agg_size = 0; + + while(kv) { + switch(kv->key.type) { + case CSR1212_KV_TYPE_LEAF: + /* Add 1 quadlet for crc/len field */ + agg_size += kv->value.leaf.len + 1; + break; + + case CSR1212_KV_TYPE_DIRECTORY: + kv->value.directory.len = csr1212_generate_layout_subdir(kv, <ail); + /* Add 1 quadlet for crc/len field */ + agg_size += kv->value.directory.len + 1; + break; + } + kv = kv->next; + } + return quads_to_bytes(agg_size); +} + +struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, + struct csr1212_keyval *start_kv, + int start_pos) +{ + struct csr1212_keyval *kv = start_kv; + struct csr1212_keyval *okv = start_kv; + int pos = start_pos; + int kv_len = 0, okv_len = 0; + + cache->layout_head = kv; + + while(kv && pos < cache->size) { + /* Special case: Extended ROM leafs */ + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { + kv->offset = cache->offset + pos; + } + + switch(kv->key.type) { + case CSR1212_KV_TYPE_LEAF: + kv_len = kv->value.leaf.len; + break; + + case CSR1212_KV_TYPE_DIRECTORY: + kv_len = kv->value.directory.len; + break; + + default: + /* Should never get here */ + break; + } + + pos += quads_to_bytes(kv_len + 1); + + if (pos <= cache->size) { + okv = kv; + okv_len = kv_len; + kv = kv->next; + } + } + + cache->layout_tail = okv; + cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1); + + return kv; +} + +static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir, + u_int32_t *data_buffer) +{ + struct csr1212_dentry *dentry; + struct csr1212_keyval *last_extkey_spec = NULL; + struct csr1212_keyval *last_extkey = NULL; + int index = 0; + + for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) { + struct csr1212_keyval *a; + + for (a = dentry->kv; a; a = a->associate) { + u_int32_t value = 0; + + /* Special Case: Extended Key Specifier_ID */ + if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { + if (last_extkey_spec == NULL) { + last_extkey_spec = a; + } else if (a->value.immediate != last_extkey_spec->value.immediate) { + last_extkey_spec = a; + } else { + continue; + } + /* Special Case: Extended Key */ + } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) { + if (last_extkey == NULL) { + last_extkey = a; + } else if (a->value.immediate != last_extkey->value.immediate) { + last_extkey = a; + } else { + continue; + } + } + + switch(a->key.type) { + case CSR1212_KV_TYPE_IMMEDIATE: + value = a->value.immediate; + break; + case CSR1212_KV_TYPE_CSR_OFFSET: + value = a->value.csr_offset; + break; + case CSR1212_KV_TYPE_LEAF: + value = a->offset; + value -= dir->offset + quads_to_bytes(1+index); + value = bytes_to_quads(value); + break; + case CSR1212_KV_TYPE_DIRECTORY: + value = a->offset; + value -= dir->offset + quads_to_bytes(1+index); + value = bytes_to_quads(value); + break; + default: + /* Should never get here */ + break; /* GDB breakpoint */ + } + + value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT; + value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) << + (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT); + data_buffer[index] = CSR1212_CPU_TO_BE32(value); + index++; + } + } +} + +void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) +{ + struct csr1212_keyval *kv, *nkv; + struct csr1212_keyval_img *kvi; + + for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) { + kvi = (struct csr1212_keyval_img *) + (cache->data + bytes_to_quads(kv->offset - cache->offset)); + switch(kv->key.type) { + default: + case CSR1212_KV_TYPE_IMMEDIATE: + case CSR1212_KV_TYPE_CSR_OFFSET: + /* Should never get here */ + break; /* GDB breakpoint */ + + case CSR1212_KV_TYPE_LEAF: + /* Don't copy over Extended ROM areas, they are + * already filled out! */ + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) + memcpy(kvi->data, kv->value.leaf.data, + quads_to_bytes(kv->value.leaf.len)); + + kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len); + kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len); + break; + + case CSR1212_KV_TYPE_DIRECTORY: + csr1212_generate_tree_subdir(kv, kvi->data); + + kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len); + kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len); + break; + } + + nkv = kv->next; + if (kv->prev) + kv->prev->next = NULL; + if (kv->next) + kv->next->prev = NULL; + kv->prev = NULL; + kv->next = NULL; + } +} + +int csr1212_generate_csr_image(struct csr1212_csr *csr) +{ + struct csr1212_bus_info_block_img *bi; + struct csr1212_csr_rom_cache *cache; + struct csr1212_keyval *kv; + size_t agg_size; + int ret; + int init_offset; + + if (!csr) + return CSR1212_EINVAL; + + cache = csr->cache_head; + + bi = (struct csr1212_bus_info_block_img*)cache->data; + + bi->length = bytes_to_quads(csr->bus_info_len) - 1; + bi->crc_length = bi->length; + bi->crc = csr1212_crc16(bi->data, bi->crc_length); + + csr->root_kv->next = NULL; + csr->root_kv->prev = NULL; + + agg_size = csr1212_generate_layout_order(csr->root_kv); + + init_offset = csr->bus_info_len; + + for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) { + if (!cache) { + /* Estimate approximate number of additional cache + * regions needed (it assumes that the cache holding + * the first 1K Config ROM space always exists). */ + int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE - + (2 * sizeof(u_int32_t))) + 1; + + /* Add additional cache regions, extras will be + * removed later */ + for (; est_c; est_c--) { + ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE); + if (ret != CSR1212_SUCCESS) + return ret; + } + /* Need to re-layout for additional cache regions */ + agg_size = csr1212_generate_layout_order(csr->root_kv); + kv = csr->root_kv; + cache = csr->cache_head; + init_offset = csr->bus_info_len; + } + kv = csr1212_generate_positions(cache, kv, init_offset); + agg_size -= cache->len; + init_offset = sizeof(u_int32_t); + } + + /* Remove unused, excess cache regions */ + while (cache) { + struct csr1212_csr_rom_cache *oc = cache; + + cache = cache->next; + csr1212_remove_cache(csr, oc); + } + + /* Go through the list backward so that when done, the correct CRC + * will be calculated for the Extended ROM areas. */ + for(cache = csr->cache_tail; cache; cache = cache->prev) { + /* Only Extended ROM caches should have this set. */ + if (cache->ext_rom) { + int leaf_size; + + /* Make sure the Extended ROM leaf is a multiple of + * max_rom in size. */ + if (csr->max_rom < 1) + return CSR1212_EINVAL; + leaf_size = (cache->len + (csr->max_rom - 1)) & + ~(csr->max_rom - 1); + + /* Zero out the unused ROM region */ + memset(cache->data + bytes_to_quads(cache->len), 0x00, + leaf_size - cache->len); + + /* Subtract leaf header */ + leaf_size -= sizeof(u_int32_t); + + /* Update the Extended ROM leaf length */ + cache->ext_rom->value.leaf.len = + bytes_to_quads(leaf_size); + } else { + /* Zero out the unused ROM region */ + memset(cache->data + bytes_to_quads(cache->len), 0x00, + cache->size - cache->len); + } + + /* Copy the data into the cache buffer */ + csr1212_fill_cache(cache); + + if (cache != csr->cache_head) { + /* Set the length and CRC of the extended ROM. */ + struct csr1212_keyval_img *kvi = + (struct csr1212_keyval_img*)cache->data; + + kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1); + kvi->crc = csr1212_crc16(kvi->data, + bytes_to_quads(cache->len) - 1); + + } + } + + return CSR1212_SUCCESS; +} + +int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len) +{ + struct csr1212_csr_rom_cache *cache; + + for (cache = csr->cache_head; cache; cache = cache->next) { + if (offset >= cache->offset && + (offset + len) <= (cache->offset + cache->size)) { + memcpy(buffer, + &cache->data[bytes_to_quads(offset - cache->offset)], + len); + return CSR1212_SUCCESS; + } + } + return CSR1212_ENOENT; +} + + + +/* Parse a chunk of data as a Config ROM */ + +static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) +{ + struct csr1212_bus_info_block_img *bi; + struct csr1212_cache_region *cr; + int i; + int ret; + + /* IEEE 1212 says that the entire bus info block should be readable in + * a single transaction regardless of the max_rom value. + * Unfortunately, many IEEE 1394 devices do not abide by that, so the + * bus info block will be read 1 quadlet at a time. The rest of the + * ConfigROM will be read according to the max_rom field. */ + for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) { + ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, + sizeof(csr1212_quad_t), + &csr->cache_head->data[bytes_to_quads(i)], + csr->private_data); + if (ret != CSR1212_SUCCESS) + return ret; + } + + bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data; + csr->crc_len = quads_to_bytes(bi->crc_length); + + /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not + * always the case, so read the rest of the crc area 1 quadlet at a time. */ + for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) { + ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, + sizeof(csr1212_quad_t), + &csr->cache_head->data[bytes_to_quads(i)], + csr->private_data); + if (ret != CSR1212_SUCCESS) + return ret; + } + + if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length) + return CSR1212_EINVAL; + +#if 0 + /* Apparently there are too many differnt wrong implementations of the + * CRC algorithm that verifying them is moot. */ + if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) && + (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc)) + return CSR1212_EINVAL; +#endif + + cr = CSR1212_MALLOC(sizeof(struct csr1212_cache_region)); + if (!cr) + return CSR1212_ENOMEM; + + cr->next = NULL; + cr->prev = NULL; + cr->offset_start = 0; + cr->offset_end = csr->crc_len + 4; + + csr->cache_head->filled_head = cr; + csr->cache_head->filled_tail = cr; + + return CSR1212_SUCCESS; +} + +static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, + csr1212_quad_t ki, + u_int32_t kv_pos) +{ + int ret = CSR1212_SUCCESS; + struct csr1212_keyval *k = NULL; + u_int32_t offset; + + switch(CSR1212_KV_KEY_TYPE(ki)) { + case CSR1212_KV_TYPE_IMMEDIATE: + k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki), + CSR1212_KV_VAL(ki)); + if (!k) { + ret = CSR1212_ENOMEM; + goto fail; + } + + k->refcnt = 0; /* Don't keep local reference when parsing. */ + break; + + case CSR1212_KV_TYPE_CSR_OFFSET: + k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki), + CSR1212_KV_VAL(ki)); + if (!k) { + ret = CSR1212_ENOMEM; + goto fail; + } + k->refcnt = 0; /* Don't keep local reference when parsing. */ + break; + + default: + /* Compute the offset from 0xffff f000 0000. */ + offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos; + if (offset == kv_pos) { + /* Uh-oh. Can't have a relative offset of 0 for Leaves + * or Directories. The Config ROM image is most likely + * messed up, so we'll just abort here. */ + ret = CSR1212_EIO; + goto fail; + } + + k = csr1212_find_keyval_offset(dir, offset); + + if (k) + break; /* Found it. */ + + if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) { + k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki)); + } else { + k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0); + } + if (!k) { + ret = CSR1212_ENOMEM; + goto fail; + } + k->refcnt = 0; /* Don't keep local reference when parsing. */ + k->valid = 0; /* Contents not read yet so it's not valid. */ + k->offset = offset; + + k->prev = dir; + k->next = dir->next; + dir->next->prev = k; + dir->next = k; + } + ret = csr1212_attach_keyval_to_directory(dir, k); + +fail: + if (ret != CSR1212_SUCCESS) { + if (k) + free_keyval(k); + } + return ret; +} + + +int csr1212_parse_keyval(struct csr1212_keyval *kv, + struct csr1212_csr_rom_cache *cache) +{ + struct csr1212_keyval_img *kvi; + int i; + int ret = CSR1212_SUCCESS; + int kvi_len; + + kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset - + cache->offset)]; + kvi_len = CSR1212_BE16_TO_CPU(kvi->length); + +#if 0 + /* Apparently there are too many differnt wrong implementations of the + * CRC algorithm that verifying them is moot. */ + if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) && + (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) { + ret = CSR1212_EINVAL; + goto fail; + } +#endif + + switch(kv->key.type) { + case CSR1212_KV_TYPE_DIRECTORY: + for (i = 0; i < kvi_len; i++) { + csr1212_quad_t ki = kvi->data[i]; + + /* Some devices put null entries in their unit + * directories. If we come across such an entry, + * then skip it. */ + if (ki == 0x0) + continue; + ret = csr1212_parse_dir_entry(kv, ki, + (kv->offset + + quads_to_bytes(i + 1))); + } + kv->value.directory.len = kvi_len; + break; + + case CSR1212_KV_TYPE_LEAF: + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { + kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len)); + if (!kv->value.leaf.data) + { + ret = CSR1212_ENOMEM; + goto fail; + } + + kv->value.leaf.len = kvi_len; + memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len)); + } + break; + } + + kv->valid = 1; + +fail: + return ret; +} + + +int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) +{ + struct csr1212_cache_region *cr, *ncr, *newcr = NULL; + struct csr1212_keyval_img *kvi = NULL; + struct csr1212_csr_rom_cache *cache; + int cache_index; + u_int64_t addr; + u_int32_t *cache_ptr; + u_int16_t kv_len = 0; + + if (!csr || !kv || csr->max_rom < 1) + return CSR1212_EINVAL; + + /* First find which cache the data should be in (or go in if not read + * yet). */ + for (cache = csr->cache_head; cache; cache = cache->next) { + if (kv->offset >= cache->offset && + kv->offset < (cache->offset + cache->size)) + break; + } + + if (!cache) { + csr1212_quad_t q; + u_int32_t cache_size; + + /* Only create a new cache for Extended ROM leaves. */ + if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) + return CSR1212_EINVAL; + + if (csr->ops->bus_read(csr, + CSR1212_REGISTER_SPACE_BASE + kv->offset, + sizeof(csr1212_quad_t), &q, csr->private_data)) { + return CSR1212_EIO; + } + + kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16; + + cache_size = (quads_to_bytes(kv->value.leaf.len + 1) + + (csr->max_rom - 1)) & ~(csr->max_rom - 1); + + cache = csr1212_rom_cache_malloc(kv->offset, cache_size); + if (!cache) + return CSR1212_ENOMEM; + + kv->value.leaf.data = &cache->data[1]; + csr->cache_tail->next = cache; + cache->prev = csr->cache_tail; + cache->next = NULL; + csr->cache_tail = cache; + cache->filled_head = + CSR1212_MALLOC(sizeof(struct csr1212_cache_region)); + if (!cache->filled_head) { + return CSR1212_ENOMEM; + } + + cache->filled_head->offset_start = 0; + cache->filled_head->offset_end = sizeof(csr1212_quad_t); + cache->filled_tail = cache->filled_head; + cache->filled_head->next = NULL; + cache->filled_head->prev = NULL; + cache->data[0] = q; + + /* Don't read the entire extended ROM now. Pieces of it will + * be read when entries inside it are read. */ + return csr1212_parse_keyval(kv, cache); + } + + cache_index = kv->offset - cache->offset; + + /* Now seach read portions of the cache to see if it is there. */ + for (cr = cache->filled_head; cr; cr = cr->next) { + if (cache_index < cr->offset_start) { + newcr = CSR1212_MALLOC(sizeof(struct csr1212_cache_region)); + if (!newcr) + return CSR1212_ENOMEM; + + newcr->offset_start = cache_index & ~(csr->max_rom - 1); + newcr->offset_end = newcr->offset_start; + newcr->next = cr; + newcr->prev = cr->prev; + cr->prev = newcr; + cr = newcr; + break; + } else if ((cache_index >= cr->offset_start) && + (cache_index < cr->offset_end)) { + kvi = (struct csr1212_keyval_img*) + (&cache->data[bytes_to_quads(cache_index)]); + kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) + + 1); + break; + } else if (cache_index == cr->offset_end) + break; + } + + if (!cr) { + cr = cache->filled_tail; + newcr = CSR1212_MALLOC(sizeof(struct csr1212_cache_region)); + if (!newcr) + return CSR1212_ENOMEM; + + newcr->offset_start = cache_index & ~(csr->max_rom - 1); + newcr->offset_end = newcr->offset_start; + newcr->prev = cr; + newcr->next = cr->next; + cr->next = newcr; + cr = newcr; + cache->filled_tail = newcr; + } + + while(!kvi || cr->offset_end < cache_index + kv_len) { + cache_ptr = &cache->data[bytes_to_quads(cr->offset_end & + ~(csr->max_rom - 1))]; + + addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset + + cr->offset_end) & ~(csr->max_rom - 1); + + if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr, + csr->private_data)) { + if (csr->max_rom == 4) + /* We've got problems! */ + return CSR1212_EIO; + + /* Apperently the max_rom value was a lie, set it to + * do quadlet reads and try again. */ + csr->max_rom = 4; + continue; + } + + cr->offset_end += csr->max_rom - (cr->offset_end & + (csr->max_rom - 1)); + + if (!kvi && (cr->offset_end > cache_index)) { + kvi = (struct csr1212_keyval_img*) + (&cache->data[bytes_to_quads(cache_index)]); + kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) + + 1); + } + + if ((kv_len + (kv->offset - cache->offset)) > cache->size) { + /* The Leaf or Directory claims its length extends + * beyond the ConfigROM image region and thus beyond the + * end of our cache region. Therefore, we abort now + * rather than seg faulting later. */ + return CSR1212_EIO; + } + + ncr = cr->next; + + if (ncr && (cr->offset_end >= ncr->offset_start)) { + /* consolidate region entries */ + ncr->offset_start = cr->offset_start; + + if (cr->prev) + cr->prev->next = cr->next; + ncr->prev = cr->prev; + if (cache->filled_head == cr) + cache->filled_head = ncr; + CSR1212_FREE(cr); + cr = ncr; + } + } + + return csr1212_parse_keyval(kv, cache); +} + + + +int csr1212_parse_csr(struct csr1212_csr *csr) +{ + static const int mr_map[] = { 4, 64, 1024, 0 }; + struct csr1212_dentry *dentry; + int ret; + + if (!csr || !csr->ops || !csr->ops->bus_read) + return CSR1212_EINVAL; + + ret = csr1212_parse_bus_info_block(csr); + if (ret != CSR1212_SUCCESS) + return ret; + + if (!csr->ops->get_max_rom) + csr->max_rom = mr_map[0]; /* default value */ + else { + int i = csr->ops->get_max_rom(csr->bus_info_data, + csr->private_data); + if (i & ~0x3) + return CSR1212_EINVAL; + csr->max_rom = mr_map[i]; + } + + csr->cache_head->layout_head = csr->root_kv; + csr->cache_head->layout_tail = csr->root_kv; + + csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) + + csr->bus_info_len; + + csr->root_kv->valid = 0; + csr->root_kv->next = csr->root_kv; + csr->root_kv->prev = csr->root_kv; + csr1212_get_keyval(csr, csr->root_kv); + + /* Scan through the Root directory finding all extended ROM regions + * and make cache regions for them */ + for (dentry = csr->root_kv->value.directory.dentries_head; + dentry; dentry = dentry->next) { + if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { + csr1212_get_keyval(csr, dentry->kv); + + if (ret != CSR1212_SUCCESS) + return ret; + } + } + + return CSR1212_SUCCESS; +} Index: /tags/2.0-rc2/src/libieee1394/IsoHandler.h =================================================================== --- /tags/2.0-rc2/src/libieee1394/IsoHandler.h (revision 1526) +++ /tags/2.0-rc2/src/libieee1394/IsoHandler.h (revision 1526) @@ -0,0 +1,232 @@ +/* + * 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 . + * + */ + +#ifndef __FFADO_ISOHANDLER__ +#define __FFADO_ISOHANDLER__ + +#include "debugmodule/debugmodule.h" + +#include "libutil/Thread.h" + +enum raw1394_iso_disposition; + +class IsoHandlerManager; +namespace Streaming { + class StreamProcessor; +} + +/*! +\brief The Base Class for ISO Handlers + + These classes perform the actual ISO communication through libraw1394. + They are different from Streaming::StreamProcessors because one handler can provide multiple + streams with packets in case of ISO multichannel receive. + +*/ + +class IsoHandler +{ +public: + enum EHandlerType { + eHT_Receive, + eHT_Transmit + }; + IsoHandler(IsoHandlerManager& manager, enum EHandlerType t); + IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, + unsigned int buf_packets, unsigned int max_packet_size, int irq); + IsoHandler(IsoHandlerManager& manager, enum EHandlerType t, + unsigned int buf_packets, unsigned int max_packet_size, int irq, enum raw1394_iso_speed speed); + ~IsoHandler(); + +private: // the ISO callback interface + static enum raw1394_iso_disposition + iso_receive_handler(raw1394handle_t handle, unsigned char *data, + unsigned int length, unsigned char channel, + unsigned char tag, unsigned char sy, unsigned int cycle, + unsigned int dropped); + + enum raw1394_iso_disposition + putPacket(unsigned char *data, unsigned int length, + unsigned char channel, unsigned char tag, unsigned char sy, + unsigned int cycle, unsigned int dropped); + + static enum raw1394_iso_disposition iso_transmit_handler(raw1394handle_t handle, + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped); + enum raw1394_iso_disposition + getPacket(unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + int cycle, unsigned int dropped, unsigned int skipped); + +public: + + /** + * Iterate the handler, transporting ISO packets to the client(s) + * @return true if success + */ + bool iterate(); + + /** + * Iterate the handler, transporting ISO packets to the client(s) + * @param ctr_now the CTR time at which the iterate call is done. + * @return true if success + */ + bool iterate(uint32_t ctr_now); + + int getFileDescriptor() { return raw1394_get_fd(m_handle);}; + + bool init(); + void setVerboseLevel(int l); + + // the enable/disable functions should only be used from within the loop that iterates() + // but not from within the iterate callback. use the requestEnable / requestDisable functions + // for that + bool enable() {return enable(-1);}; + bool enable(int cycle); + bool disable(); + + // functions to request enable or disable at the next opportunity + bool requestEnable(int cycle = -1); + bool requestDisable(); + + /** + * updates the internal state if required + */ + void updateState(); + + enum EHandlerType getType() {return m_type;}; + const char *getTypeString() {return eHTToString(m_type); }; + + // pretty printing + const char *eHTToString(enum EHandlerType); + + bool isEnabled() + {return m_State == eHS_Running;}; + + // no setter functions, because those would require a re-init + unsigned int getMaxPacketSize() { return m_max_packet_size;}; + unsigned int getNbBuffers() { return m_buf_packets;}; + int getIrqInterval() { return m_irq_interval;}; + + unsigned int getPreBuffers() {return m_prebuffers;}; + void setPreBuffers(unsigned int n) {m_prebuffers=n;}; + + void dumpInfo(); + + bool inUse() {return (m_Client != 0) ;}; + bool isStreamRegistered(Streaming::StreamProcessor *s) {return (m_Client == s);}; + + bool registerStream(Streaming::StreamProcessor *); + bool unregisterStream(Streaming::StreamProcessor *); + + bool canIterateClient(); // FIXME: implement with functor + + /** + * @brief request that the handler exits the packet processing loop ASAP + * + * The raw1394 lib doesn't provide a means to stop the packet iteration loop + * except when the iterate callback returns a DEFER value. Calling this function + * will make the callback return DEFER ASAP. + */ + void requestIterateLoopExit() {m_dont_exit_iterate_loop = false;}; + /** + * @brief allow the handler to stay in the packet processing loop + * + * This resets the state set by requestIterateLoopExit() + */ + void allowIterateLoop() {m_dont_exit_iterate_loop = true;}; + + + /** + * @brief get last cycle number seen by handler + * @return cycle number + */ + int getLastCycle() {return m_last_cycle;}; + + /** + * @brief returns the CTR value saved at the last iterate() call + * @return CTR value saved at last iterate() call + */ + uint32_t getLastIterateTime() {return m_last_now;}; + + /** + * @brief returns the CTR value saved at the last iterate handler call + * @return CTR value saved at last iterate handler call + */ + uint32_t getLastPacketTime() {return m_last_packet_handled_at;}; + + /** + * @brief set iso receive mode. doesn't have any effect if the stream is running + * @param m receive mode + */ + void setReceiveMode(enum raw1394_iso_dma_recv_mode m) + {m_receive_mode = m;} + + void notifyOfDeath(); + bool handleBusReset(); + +private: + IsoHandlerManager& m_manager; + enum EHandlerType m_type; + raw1394handle_t m_handle; + unsigned int m_buf_packets; + unsigned int m_max_packet_size; + int m_irq_interval; + int m_last_cycle; + uint32_t m_last_now; + uint32_t m_last_packet_handled_at; + enum raw1394_iso_dma_recv_mode m_receive_mode; + + Streaming::StreamProcessor *m_Client; // FIXME: implement with functors + + enum raw1394_iso_speed m_speed; + unsigned int m_prebuffers; + bool m_dont_exit_iterate_loop; + + // the state machine + enum EHandlerStates { + eHS_Stopped, + eHS_Running, + eHS_Error, + }; + enum EHandlerStates m_State; + enum EHandlerStates m_NextState; + int m_switch_on_cycle; + +public: + unsigned int m_packets; + #ifdef DEBUG + unsigned int m_dropped; + unsigned int m_skipped; + int m_min_ahead; + #endif + +protected: + DECLARE_DEBUG_MODULE; +}; + +#endif /* __FFADO_ISOHANDLER__ */ + + + Index: /tags/2.0-rc2/src/ffadodevice.cpp =================================================================== --- /tags/2.0-rc2/src/ffadodevice.cpp (revision 1474) +++ /tags/2.0-rc2/src/ffadodevice.cpp (revision 1474) @@ -0,0 +1,273 @@ +/* + * 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 . + * + */ + +#include "ffadodevice.h" +#include "devicemanager.h" + +#include "libieee1394/configrom.h" +#include "libieee1394/ieee1394service.h" + +#include "libcontrol/Element.h" +#include "libcontrol/ClockSelect.h" +#include "libcontrol/Nickname.h" + +#include +#include + +#include + +IMPL_DEBUG_MODULE( FFADODevice, FFADODevice, DEBUG_LEVEL_NORMAL ); + +FFADODevice::FFADODevice( DeviceManager& d, std::auto_ptr( configRom ) ) + : Control::Container(&d) + , m_pConfigRom( configRom ) + , m_pDeviceManager( d ) +{ + addOption(Util::OptionContainer::Option("id",std::string("dev?"))); + + std::ostringstream nodestr; + nodestr << "node" << getConfigRom().getNodeId(); + + if (!addElement(&getConfigRom())) { + debugWarning("failed to add ConfigRom to Control::Container\n"); + } + + m_genericContainer = new Control::Container(this, "Generic"); + if(m_genericContainer == NULL) { + debugError("Could not create Control::Container for generic controls\n"); + } else { + + if (!addElement(m_genericContainer)) { + debugWarning("failed to add generic container to Control::Container\n"); + } + // add a generic control for the clock source selection + if(!m_genericContainer->addElement(new Control::ClockSelect(*this))) { + debugWarning("failed to add clock source control to container\n"); + } + // add a generic control for the sample rate selection + if(!m_genericContainer->addElement(new Control::SamplerateSelect(*this))) { + debugWarning("failed to add sample rate control to container\n"); + } + // add a generic control for the nickname + if(!m_genericContainer->addElement(new Control::Nickname(*this))) { + debugWarning("failed to add Nickname control to container\n"); + } + // add a generic control for the streaming status + if(!m_genericContainer->addElement(new Control::StreamingStatus(*this))) { + debugWarning("failed to add StreamingStatus control to container\n"); + } + } +} + +FFADODevice::~FFADODevice() +{ + if (!deleteElement(&getConfigRom())) { + debugWarning("failed to remove ConfigRom from Control::Container\n"); + } + + // remove generic controls if present + if(m_genericContainer) { + if (!deleteElement(m_genericContainer)) { + debugError("Generic controls present but not registered to the avdevice\n"); + } + // remove and delete (as in free) child control elements + m_genericContainer->clearElements(true); + delete m_genericContainer; + } +} + +FFADODevice * +FFADODevice::createDevice(std::auto_ptr( x )) +{ + // re-implement this!! + assert(0); + return NULL; +} + +std::string +FFADODevice::getName() +{ + return getConfigRom().getGuidString(); +} + +int +FFADODevice::getNodeId() +{ + return getConfigRom().getNodeId(); +} + +bool FFADODevice::compareGUID( FFADODevice *a, FFADODevice *b ) { + assert(a); + assert(b); + return ConfigRom::compareGUID(a->getConfigRom(), b->getConfigRom()); +} + +ConfigRom& +FFADODevice::getConfigRom() const +{ + return *m_pConfigRom; +} + +Ieee1394Service& +FFADODevice::get1394Service() +{ + return getConfigRom().get1394Service(); +} + +bool +FFADODevice::loadFromCache() +{ + return false; +} + +bool +FFADODevice::saveCache() +{ + return false; +} + +bool +FFADODevice::needsRediscovery() +{ + // require rediscovery by default + return true; +} + +enum FFADODevice::eSyncState +FFADODevice::getSyncState( ) { + return eSS_Unknown; +} + +enum FFADODevice::eStreamingState +FFADODevice::getStreamingState() +{ + return eSS_Idle; +} + +bool +FFADODevice::setId( unsigned int id) +{ + Util::MutexLockHelper lock(m_DeviceMutex); + bool retval; + // FIXME: decent ID system nescessary + std::ostringstream idstr; + idstr << "dev" << id; + debugOutput( DEBUG_LEVEL_VERBOSE, "Set id to %s...\n", idstr.str().c_str()); + + retval=setOption("id",idstr.str()); + return retval; +} + +bool +FFADODevice::setNickname( std::string name) +{ + return false; +} + +std::string +FFADODevice::getNickname() +{ + return "Unsupported"; +} + +bool +FFADODevice::canChangeNickname() +{ + return false; +} + +void +FFADODevice::handleBusReset() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Handle bus reset...\n"); + + // update the config rom node id + sleep(1); + + Util::MutexLockHelper lock(m_DeviceMutex); + getConfigRom().setVerboseLevel(getDebugLevel()); + getConfigRom().updatedNodeId(); +} + +void +FFADODevice::setVerboseLevel(int l) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l ); + setDebugLevel(l); + m_DeviceMutex.setVerboseLevel(l); + getConfigRom().setVerboseLevel(l); +} + +void +FFADODevice::showDevice() +{ + #ifdef DEBUG + Ieee1394Service& s = getConfigRom().get1394Service(); + debugOutput(DEBUG_LEVEL_NORMAL, "Attached to port.......: %d (%s)\n", + s.getPort(), s.getPortName().c_str()); + debugOutput(DEBUG_LEVEL_NORMAL, "Node...................: %d\n", getNodeId()); + debugOutput(DEBUG_LEVEL_NORMAL, "Vendor name............: %s\n", + getConfigRom().getVendorName().c_str()); + debugOutput(DEBUG_LEVEL_NORMAL, "Model name.............: %s\n", + getConfigRom().getModelName().c_str()); + debugOutput(DEBUG_LEVEL_NORMAL, "GUID...................: %s\n", + getConfigRom().getGuidString().c_str()); + + std::string id=std::string("dev? [none]"); + getOption("id", id); + + debugOutput(DEBUG_LEVEL_NORMAL, "Assigned ID....: %s\n", id.c_str()); + + flushDebugOutput(); + #endif +} + + +bool +FFADODevice::enableStreaming() { + return true; +} + +bool +FFADODevice::disableStreaming() { + return true; +} + +const char * +FFADODevice::ClockSourceTypeToString(enum eClockSourceType t) +{ + switch(t) { + default: return "Erratic type "; + case eCT_Invalid: return "Invalid "; + case eCT_Internal: return "Internal "; + case eCT_1394Bus: return "1394 Bus "; + case eCT_SytMatch: return "Compound Syt Match"; + case eCT_SytStream: return "Sync Syt Match "; + case eCT_WordClock: return "WordClock "; + case eCT_SPDIF: return "SPDIF "; + case eCT_ADAT: return "ADAT "; + case eCT_TDIF: return "TDIF "; + case eCT_AES: return "AES "; + } +} Index: /tags/2.0-rc2/src/devicemanager.h =================================================================== --- /tags/2.0-rc2/src/devicemanager.h (revision 1561) +++ /tags/2.0-rc2/src/devicemanager.h (revision 1561) @@ -0,0 +1,197 @@ +/* + * 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 . + * + */ + +#ifndef FFADODEVICEMANAGER_H +#define FFADODEVICEMANAGER_H + +#include "debugmodule/debugmodule.h" + +#include "libieee1394/configrom.h" +#include "libieee1394/ieee1394service.h" + +#include "libstreaming/StreamProcessorManager.h" + +#include "libutil/OptionContainer.h" +#include "libcontrol/BasicElements.h" + +#include "libutil/Functors.h" +#include "libutil/Mutex.h" +#include "libutil/Configuration.h" + +#include +#include + +class Ieee1394Service; +class FFADODevice; +class DeviceStringParser; + +namespace Streaming { + class StreamProcessor; +} + +typedef std::vector< FFADODevice* > FFADODeviceVector; +typedef std::vector< FFADODevice* >::iterator FFADODeviceVectorIterator; + +typedef std::vector< Ieee1394Service* > Ieee1394ServiceVector; +typedef std::vector< Ieee1394Service* >::iterator Ieee1394ServiceVectorIterator; + +typedef std::vector< Util::Functor* > FunctorVector; +typedef std::vector< Util::Functor* >::iterator FunctorVectorIterator; + +typedef std::vector< ConfigRom* > ConfigRomVector; +typedef std::vector< ConfigRom* >::iterator ConfigRomVectorIterator; + +class DeviceManager + : public Util::OptionContainer, + public Control::Container +{ +public: + enum eWaitResult { + eWR_OK, + eWR_Xrun, + eWR_Error, + eWR_Shutdown, + }; + + DeviceManager(); + ~DeviceManager(); + + bool setThreadParameters(bool rt, int priority); + + bool initialize(); + bool deinitialize(); + + bool addSpecString(char *); + bool isSpecStringValid(std::string s); + + bool discover(bool useCache=true, bool rediscover=false); + bool initStreaming(); + bool prepareStreaming(); + bool finishStreaming(); + bool startStreamingOnDevice(FFADODevice *device); + bool startStreaming(); + bool stopStreamingOnDevice(FFADODevice *device); + bool stopStreaming(); + bool resetStreaming(); + enum eWaitResult waitForPeriod(); + bool setStreamingParams(unsigned int period, unsigned int rate, unsigned int nb_buffers); + + bool isValidNode( int node ); + int getNbDevices(); + int getDeviceNodeId( int deviceNr ); + + FFADODevice* getAvDevice( int nodeId ); + FFADODevice* getAvDeviceByIndex( int idx ); + unsigned int getAvDeviceCount(); + + Streaming::StreamProcessor *getSyncSource(); + + /** + * prevents the busreset handler from running. use with care! + */ + void lockBusResetHandler() {m_BusResetLock->Lock();}; + /** + * releases the busreset handlers + */ + void unlockBusResetHandler() {m_BusResetLock->Unlock();}; + bool registerBusresetNotification(Util::Functor *f) + {return registerNotification(m_busResetNotifiers, f);}; + bool unregisterBusresetNotification(Util::Functor *f) + {return unregisterNotification(m_busResetNotifiers, f);}; + + bool registerPreUpdateNotification(Util::Functor *f) + {return registerNotification(m_preUpdateNotifiers, f);}; + bool unregisterPreUpdateNotification(Util::Functor *f) + {return unregisterNotification(m_preUpdateNotifiers, f);}; + + bool registerPostUpdateNotification(Util::Functor *f) + {return registerNotification(m_postUpdateNotifiers, f);}; + bool unregisterPostUpdateNotification(Util::Functor *f) + {return unregisterNotification(m_postUpdateNotifiers, f);}; + + + Util::Configuration& getConfiguration() {return *m_configuration;}; + + void showDeviceInfo(); + void showStreamingInfo(); + + // the Control::Container functions + virtual std::string getName() + {return "DeviceManager";}; + virtual bool setName( std::string n ) + { return false;}; + +protected: + FFADODevice* getDriverForDeviceDo( ConfigRom *configRom, + int id, bool generic ); + FFADODevice* getDriverForDevice( ConfigRom *configRom, + int id ); + FFADODevice* getSlaveDriver( std::auto_ptr( configRom ) ); + + void busresetHandler(Ieee1394Service &); + +protected: + // we have one service for each port + // found on the system. We don't allow dynamic addition of ports (yet) + Ieee1394ServiceVector m_1394Services; + FFADODeviceVector m_avDevices; + FunctorVector m_busreset_functors; + + // the lock protecting the device list + Util::Mutex* m_DeviceListLock; + // the lock to serialize bus reset handling + Util::Mutex* m_BusResetLock; + +public: // FIXME: this should be better + Streaming::StreamProcessorManager& getStreamProcessorManager() + {return *m_processorManager;}; +private: + Streaming::StreamProcessorManager* m_processorManager; + DeviceStringParser* m_deviceStringParser; + Util::Configuration* m_configuration; + bool m_used_cache_last_time; + + typedef std::vector< Util::Functor* > notif_vec_t; + notif_vec_t m_busResetNotifiers; + notif_vec_t m_preUpdateNotifiers; + notif_vec_t m_postUpdateNotifiers; + + bool registerNotification(notif_vec_t&, Util::Functor *); + bool unregisterNotification(notif_vec_t&, Util::Functor *); + void signalNotifiers(notif_vec_t& list); + +protected: + std::vector m_SpecStrings; + + bool m_thread_realtime; + int m_thread_priority; + +// debug stuff +public: + void setVerboseLevel(int l); +private: + DECLARE_DEBUG_MODULE; +}; + +#endif Index: /tags/2.0-rc2/src/libstreaming/motu/MotuPort.h =================================================================== --- /tags/2.0-rc2/src/libstreaming/motu/MotuPort.h (revision 864) +++ /tags/2.0-rc2/src/libstreaming/motu/MotuPort.h (revision 864) @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#ifndef __FFADO_MOTUPORT__ +#define __FFADO_MOTUPORT__ + +/** + * This file implements the ports used in Motu devices + */ + +#include "MotuPortInfo.h" +#include "../generic/Port.h" + +#include "debugmodule/debugmodule.h" + +namespace Streaming { + +/*! +\brief The Base Class for Motu Audio Port + + +*/ +class MotuAudioPort + : public AudioPort, public MotuPortInfo +{ + +public: + + MotuAudioPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position, + int size) + : AudioPort(m, name, direction), + MotuPortInfo( position, size) // TODO: add more port information parameters here if nescessary + {}; + + virtual ~MotuAudioPort() {}; +}; + +/*! +\brief The Base Class for an Motu Midi Port + + +*/ +class MotuMidiPort + : public MidiPort, public MotuPortInfo +{ + +public: + + MotuMidiPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position) + : MidiPort(m, name, direction), + MotuPortInfo(position, 0) // TODO: add more port information parameters here if nescessary + {}; + + virtual ~MotuMidiPort() {}; +}; + +/*! +\brief The Base Class for an Motu Control Port + + +*/ +class MotuControlPort + : public ControlPort, public MotuPortInfo +{ + +public: + + MotuControlPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position) + : ControlPort(m, name, direction), + MotuPortInfo(position, 2) // TODO: add more port information parameters here if nescessary + {}; + + virtual ~MotuControlPort() {}; +}; + +} // end of namespace Streaming + +#endif /* __FFADO_MOTUPORT__ */ + Index: /tags/2.0-rc2/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp =================================================================== --- /tags/2.0-rc2/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp (revision 1489) +++ /tags/2.0-rc2/src/libstreaming/motu/MotuTransmitStreamProcessor.cpp (revision 1489) @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#include "config.h" +#include "libutil/float_cast.h" + +#include "MotuTransmitStreamProcessor.h" +#include "MotuPort.h" +#include "../StreamProcessorManager.h" +#include "devicemanager.h" + +#include "libieee1394/ieee1394service.h" +#include "libieee1394/IsoHandlerManager.h" +#include "libieee1394/cycletimer.h" + +#include "libutil/ByteSwap.h" + +#include +#include + +/* Provide more intuitive access to GCC's branch predition built-ins */ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +namespace Streaming +{ + +// A macro to extract specific bits from a native endian quadlet +#define get_bits(_d,_start,_len) (((_d)>>((_start)-(_len)+1)) & ((1<<(_len))-1)) + +// Convert a full timestamp into an SPH timestamp as required by the MOTU +static inline uint32_t fullTicksToSph(int64_t timestamp) { + return TICKS_TO_CYCLE_TIMER(timestamp) & 0x1ffffff; +} + +/* transmit */ +MotuTransmitStreamProcessor::MotuTransmitStreamProcessor(FFADODevice &parent, unsigned int event_size ) + : StreamProcessor(parent, ePT_Transmit ) + , m_event_size( event_size ) + , m_tx_dbc( 0 ) + , mb_head( 0 ) + , mb_tail( 0 ) + , midi_lock( 0 ) +{ + int srate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate(); + /* Work out how many audio samples should be left between MIDI data bytes in order + * to stay under the MIDI hardware baud rate of 31250. MIDI data is transmitted + * using 10 bits per byte (including the start/stop bit) so this gives us 3125 bytes + * per second. If we send to the MOTU at a faster rate than this, some MIDI bytes + * will be dropped or corrupted in interesting ways. + */ + midi_tx_period = lrintf(ceil((float)srate / 3125)); +} + +unsigned int +MotuTransmitStreamProcessor::getMaxPacketSize() { + int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate(); + return framerate<=48000?616:(framerate<=96000?1032:1160); +} + +unsigned int +MotuTransmitStreamProcessor::getNominalFramesPerPacket() { + int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate(); + return framerate<=48000?8:(framerate<=96000?16:32); +} + +enum StreamProcessor::eChildReturnValue +MotuTransmitStreamProcessor::generatePacketHeader ( + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr ) +{ + unsigned int cycle = CYCLE_TIMER_GET_CYCLES(pkt_ctr); + + // The number of events per packet expected by the MOTU is solely + // dependent on the current sample rate. An 'event' is one sample from + // all channels plus possibly other midi and control data. + signed n_events = getNominalFramesPerPacket(); + + // Do housekeeping expected for all packets sent to the MOTU, even + // for packets containing no audio data. + *sy = 0x00; + *tag = 1; // All MOTU packets have a CIP-like header + *length = n_events*m_event_size + 8; + + signed int fc; + uint64_t presentation_time; + unsigned int presentation_cycle; + int cycles_until_presentation; + + uint64_t transmit_at_time; + unsigned int transmit_at_cycle; + int cycles_until_transmit; + + debugOutput ( DEBUG_LEVEL_ULTRA_VERBOSE, "Try for cycle %d\n", cycle ); + // check whether the packet buffer has packets for us to send. + // the base timestamp is the one of the next sample in the buffer + ffado_timestamp_t ts_head_tmp; + m_data_buffer->getBufferHeadTimestamp ( &ts_head_tmp, &fc ); // thread safe + + // the timestamp gives us the time at which we want the sample block + // to be output by the device + presentation_time = ( uint64_t ) ts_head_tmp; + + // now we calculate the time when we have to transmit the sample block + transmit_at_time = substractTicks ( presentation_time, MOTU_TRANSMIT_TRANSFER_DELAY ); + + // calculate the cycle this block should be presented in + // (this is just a virtual calculation since at that time it should + // already be in the device's buffer) + presentation_cycle = ( unsigned int ) ( TICKS_TO_CYCLES ( presentation_time ) ); + + // calculate the cycle this block should be transmitted in + transmit_at_cycle = ( unsigned int ) ( TICKS_TO_CYCLES ( transmit_at_time ) ); + + // we can check whether this cycle is within the 'window' we have + // to send this packet. + // first calculate the number of cycles left before presentation time + cycles_until_presentation = diffCycles ( presentation_cycle, cycle ); + + // we can check whether this cycle is within the 'window' we have + // to send this packet. + // first calculate the number of cycles left before presentation time + cycles_until_transmit = diffCycles ( transmit_at_cycle, cycle ); + + // two different options: + // 1) there are not enough frames for one packet + // => determine wether this is a problem, since we might still + // have some time to send it + // 2) there are enough packets + // => determine whether we have to send them in this packet + if ( fc < ( signed int ) getNominalFramesPerPacket() ) + { + // not enough frames in the buffer, + + // we can still postpone the queueing of the packets + // if we are far enough ahead of the presentation time + if ( cycles_until_presentation <= MOTU_MIN_CYCLES_BEFORE_PRESENTATION ) + { + debugOutput ( DEBUG_LEVEL_VERBOSE, + "Insufficient frames (P): N=%02d, CY=%04u, TC=%04u, CUT=%04d\n", + fc, cycle, transmit_at_cycle, cycles_until_transmit ); + // we are too late + return eCRV_XRun; + } + else + { + debugOutput ( DEBUG_LEVEL_VERY_VERBOSE, + "Insufficient frames (NP): N=%02d, CY=%04u, TC=%04u, CUT=%04d\n", + fc, cycle, transmit_at_cycle, cycles_until_transmit ); + // there is still time left to send the packet + // we want the system to give this packet another go at a later time instant + return eCRV_Again; + } + } + else + { + // there are enough frames, so check the time they are intended for + // all frames have a certain 'time window' in which they can be sent + // this corresponds to the range of the timestamp mechanism: + // we can send a packet 15 cycles in advance of the 'presentation time' + // in theory we can send the packet up till one cycle before the presentation time, + // however this is not very smart. + + // There are 3 options: + // 1) the frame block is too early + // => send an empty packet + // 2) the frame block is within the window + // => send it + // 3) the frame block is too late + // => discard (and raise xrun?) + // get next block of frames and repeat + + if(cycles_until_transmit < 0) + { + // we are too late + debugOutput(DEBUG_LEVEL_VERBOSE, + "Too late: CY=%04u, TC=%04u, CUT=%04d, TSP=%011llu (%04u)\n", + cycle, + transmit_at_cycle, cycles_until_transmit, + presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time) ); + + // however, if we can send this sufficiently before the presentation + // time, it could be harmless. + // NOTE: dangerous since the device has no way of reporting that it didn't get + // this packet on time. + if(cycles_until_presentation >= MOTU_MIN_CYCLES_BEFORE_PRESENTATION) + { + // we are not that late and can still try to transmit the packet + m_tx_dbc += fillDataPacketHeader((quadlet_t *)data, length, presentation_time); + m_last_timestamp = presentation_time; + if (m_tx_dbc > 0xff) + m_tx_dbc -= 0x100; + return eCRV_Packet; + } + else // definitely too late + { + return eCRV_XRun; + } + } + else if(cycles_until_transmit <= MOTU_MAX_CYCLES_TO_TRANSMIT_EARLY) + { + // it's time send the packet + m_tx_dbc += fillDataPacketHeader((quadlet_t *)data, length, presentation_time); + m_last_timestamp = presentation_time; + if (m_tx_dbc > 0xff) + m_tx_dbc -= 0x100; + return eCRV_Packet; + } + else + { + debugOutput ( DEBUG_LEVEL_VERY_VERBOSE, + "Too early: CY=%04u, TC=%04u, CUT=%04d, TST=%011llu (%04u), TSP=%011llu (%04u)\n", + cycle, + transmit_at_cycle, cycles_until_transmit, + transmit_at_time, ( unsigned int ) TICKS_TO_CYCLES ( transmit_at_time ), + presentation_time, ( unsigned int ) TICKS_TO_CYCLES ( presentation_time ) ); +#ifdef DEBUG + if ( cycles_until_transmit > MOTU_MAX_CYCLES_TO_TRANSMIT_EARLY + 1 ) + { + debugOutput ( DEBUG_LEVEL_VERY_VERBOSE, + "Way too early: CY=%04u, TC=%04u, CUT=%04d, TST=%011llu (%04u), TSP=%011llu (%04u)\n", + cycle, + transmit_at_cycle, cycles_until_transmit, + transmit_at_time, ( unsigned int ) TICKS_TO_CYCLES ( transmit_at_time ), + presentation_time, ( unsigned int ) TICKS_TO_CYCLES ( presentation_time ) ); + } +#endif + // we are too early, send only an empty packet + return eCRV_EmptyPacket; + } + } + return eCRV_Invalid; +} + +enum StreamProcessor::eChildReturnValue +MotuTransmitStreamProcessor::generatePacketData ( + unsigned char *data, unsigned int *length) +{ + quadlet_t *quadlet = (quadlet_t *)data; + quadlet += 2; // skip the header + // Size of a single data frame in quadlets + unsigned dbs = m_event_size / 4; + + // The number of events per packet expected by the MOTU is solely + // dependent on the current sample rate. An 'event' is one sample from + // all channels plus possibly other midi and control data. + signed n_events = getNominalFramesPerPacket(); + + if (m_data_buffer->readFrames(n_events, (char *)(data + 8))) { + float ticks_per_frame = m_Parent.getDeviceManager().getStreamProcessorManager().getSyncSource().getTicksPerFrame(); + + for (int i=0; i < n_events; i++, quadlet += dbs) { + int64_t ts_frame = addTicks(m_last_timestamp, (unsigned int)lrintf(i * ticks_per_frame)); + *quadlet = CondSwapToBus32(fullTicksToSph(ts_frame)); + } + + return eCRV_OK; + } + else return eCRV_XRun; + +} + +enum StreamProcessor::eChildReturnValue +MotuTransmitStreamProcessor::generateEmptyPacketHeader ( + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr ) +{ + debugOutput ( DEBUG_LEVEL_VERY_VERBOSE, "XMIT EMPTY: CY=%04u, TSP=%011llu (%04u)\n", + CYCLE_TIMER_GET_CYCLES(pkt_ctr), m_last_timestamp, + ( unsigned int ) TICKS_TO_CYCLES ( m_last_timestamp ) ); + + // Do housekeeping expected for all packets sent to the MOTU, even + // for packets containing no audio data. + *sy = 0x00; + *tag = 1; // All MOTU packets have a CIP-like header + *length = 8; + + m_tx_dbc += fillNoDataPacketHeader ( (quadlet_t *)data, length ); + return eCRV_OK; +} + +enum StreamProcessor::eChildReturnValue +MotuTransmitStreamProcessor::generateEmptyPacketData ( + unsigned char *data, unsigned int *length) +{ + return eCRV_OK; // no need to do anything +} + +enum StreamProcessor::eChildReturnValue +MotuTransmitStreamProcessor::generateSilentPacketHeader ( + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr ) +{ + unsigned int cycle = CYCLE_TIMER_GET_CYCLES(pkt_ctr); + + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "XMIT SILENT: CY=%04u, TSP=%011llu (%04u)\n", + cycle, m_last_timestamp, + ( unsigned int ) TICKS_TO_CYCLES ( m_last_timestamp ) ); + + // A "silent" packet is identical to a regular data packet except all + // audio data is set to zero. The MOTU expects valid timestamps and + // rate control in silent packets, so much of the timing logic from + // generatePacketHeader() is needed here too - the main difference being + // the source of the packet timestamp. + + // The number of events per packet expected by the MOTU is solely + // dependent on the current sample rate. An 'event' is one sample from + // all channels plus possibly other midi and control data. + signed n_events = getNominalFramesPerPacket(); + + // Do housekeeping expected for all packets sent to the MOTU, even + // for packets containing no audio data. + *sy = 0x00; + *tag = 1; // All MOTU packets have a CIP-like header + + /* Assume the packet will have audio data. If it turns out we need an empty packet + * the length will be overridden by fillNoDataPacketHeader(). + */ + *length = n_events*m_event_size + 8; + + uint64_t presentation_time; + unsigned int presentation_cycle; + int cycles_until_presentation; + + uint64_t transmit_at_time; + unsigned int transmit_at_cycle; + int cycles_until_transmit; + + /* The sample buffer is not necessarily running when silent packets are + * needed, so use m_last_timestamp (the timestamp of the previously sent + * data packet) as the basis for the presentation time of the next + * packet. Since we're only writing zeros we don't have to deal with + * buffer xruns. + */ + float ticks_per_frame = m_Parent.getDeviceManager().getStreamProcessorManager().getSyncSource().getTicksPerFrame(); + presentation_time = addTicks(m_last_timestamp, (unsigned int)lrintf(n_events * ticks_per_frame)); + + transmit_at_time = substractTicks(presentation_time, MOTU_TRANSMIT_TRANSFER_DELAY); + presentation_cycle = (unsigned int)(TICKS_TO_CYCLES(presentation_time)); + transmit_at_cycle = (unsigned int)(TICKS_TO_CYCLES(transmit_at_time)); + cycles_until_presentation = diffCycles(presentation_cycle, cycle); + cycles_until_transmit = diffCycles(transmit_at_cycle, cycle); + + if (cycles_until_transmit < 0) + { + if (cycles_until_presentation >= MOTU_MIN_CYCLES_BEFORE_PRESENTATION) + { + m_last_timestamp = presentation_time; + m_tx_dbc += fillDataPacketHeader((quadlet_t *)data, length, m_last_timestamp); + if (m_tx_dbc > 0xff) + m_tx_dbc -= 0x100; + return eCRV_Packet; + } + else + { + return eCRV_XRun; + } + } + else if (cycles_until_transmit <= MOTU_MAX_CYCLES_TO_TRANSMIT_EARLY) + { + m_last_timestamp = presentation_time; + m_tx_dbc += fillDataPacketHeader((quadlet_t *)data, length, m_last_timestamp); + if (m_tx_dbc > 0xff) + m_tx_dbc -= 0x100; + return eCRV_Packet; + } + else + { + return eCRV_EmptyPacket; + } + return eCRV_Invalid; +} + +enum StreamProcessor::eChildReturnValue +MotuTransmitStreamProcessor::generateSilentPacketData ( + unsigned char *data, unsigned int *length ) +{ + // Simply set all audio data to zero since that's what's meant by + // a "silent" packet. Note that m_event_size is in bytes for MOTU. + + quadlet_t *quadlet = (quadlet_t *)data; + quadlet += 2; // skip the header + // Size of a single data frame in quadlets + unsigned dbs = m_event_size / 4; + + // The number of events per packet expected by the MOTU is solely + // dependent on the current sample rate. An 'event' is one sample from + // all channels plus possibly other midi and control data. + signed n_events = getNominalFramesPerPacket(); + + memset(quadlet, 0, n_events*m_event_size); + float ticks_per_frame = m_Parent.getDeviceManager().getStreamProcessorManager().getSyncSource().getTicksPerFrame(); + + // Set up each frames's SPH. + for (int i=0; i < n_events; i++, quadlet += dbs) { + int64_t ts_frame = addTicks(m_last_timestamp, (unsigned int)lrintf(i * ticks_per_frame)); + *quadlet = CondSwapToBus32(fullTicksToSph(ts_frame)); + } + return eCRV_OK; +} + +unsigned int MotuTransmitStreamProcessor::fillDataPacketHeader ( + quadlet_t *data, unsigned int* length, + uint32_t ts ) +{ + quadlet_t *quadlet = (quadlet_t *)data; + // Size of a single data frame in quadlets. For data sent TO the + // Ultralite this is not strictly true (with m_event_size 52, dbs is set + // to 13, even though data sent by the Ultralite uses 19 as one would + // expect from a 52-byte event). Even so, we'll run with the assumption + // that a different dbs will be fine unless proven otherwise. + unsigned dbs = m_event_size / 4; + + // The number of events per packet expected by the MOTU is solely + // dependent on the current sample rate. An 'event' is one sample from + // all channels plus possibly other midi and control data. + signed n_events = getNominalFramesPerPacket(); + + // construct the packet CIP-like header. Even if this is a data-less + // packet the dbs field is still set as if there were data blocks + // present. For data-less packets the dbc is the same as the previously + // transmitted block. + *quadlet = CondSwapToBus32(0x00000400 | ((m_Parent.get1394Service().getLocalNodeId()&0x3f)<<24) | m_tx_dbc | (dbs<<16)); + quadlet++; + *quadlet = CondSwapToBus32(0x8222ffff); + quadlet++; + return n_events; +} + +unsigned int MotuTransmitStreamProcessor::fillNoDataPacketHeader ( + quadlet_t *data, unsigned int* length ) +{ + quadlet_t *quadlet = (quadlet_t *)data; + // Size of a single data frame in quadlets. See comment in + // fillDataPacketHeader() regarding the Ultralite. + unsigned dbs = m_event_size / 4; + // construct the packet CIP-like header. Even if this is a data-less + // packet the dbs field is still set as if there were data blocks + // present. For data-less packets the dbc is the same as the previously + // transmitted block. + *quadlet = CondSwapToBus32(0x00000400 | ((m_Parent.get1394Service().getLocalNodeId()&0x3f)<<24) | m_tx_dbc | (dbs<<16)); + quadlet++; + *quadlet = CondSwapToBus32(0x8222ffff); + quadlet++; + *length = 8; + return 0; +} + +bool MotuTransmitStreamProcessor::prepareChild() +{ + debugOutput ( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this ); + return true; +} + +/* +* compose the event streams for the packets from the port buffers +*/ +bool MotuTransmitStreamProcessor::processWriteBlock(char *data, + unsigned int nevents, unsigned int offset) { + bool no_problem=true; + unsigned int i; + + // Start with MIDI and control streams all zeroed. Due to the sparce nature + // of these streams it is best to simply fill them in on an as-needs basis. + for (i=0; iisDisabled()) { + if (encodeSilencePortToMotuEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not encode silence for disabled port %s to Motu events\n",(*it)->getName().c_str()); + // Don't treat this as a fatal error at this point + } + continue; + } + + Port *port=(*it); + + switch(port->getPortType()) { + + case Port::E_Audio: + if (encodePortToMotuEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not encode port %s to Motu events\n",(*it)->getName().c_str()); + no_problem=false; + } + break; + case Port::E_Midi: + if (encodePortToMotuMidiEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not encode port %s to Midi events\n",(*it)->getName().c_str()); + no_problem=false; + } + break; + default: // ignore + break; + } + } + return no_problem; +} + +bool +MotuTransmitStreamProcessor::transmitSilenceBlock(char *data, + unsigned int nevents, unsigned int offset) { + // This is the same as the non-silence version, except that is + // doesn't read from the port buffers. + bool no_problem = true; + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); + ++it ) { + Port *port=(*it); + + switch(port->getPortType()) { + + case Port::E_Audio: + if (encodeSilencePortToMotuEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not encode port %s to MBLA events\n",(*it)->getName().c_str()); + no_problem = false; + } + break; + case Port::E_Midi: + if (encodeSilencePortToMotuMidiEvents(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not encode port %s to Midi events\n",(*it)->getName().c_str()); + no_problem = false; + } + break; + default: // ignore + break; + } + } + return no_problem; +} + +int MotuTransmitStreamProcessor::encodePortToMotuEvents(MotuAudioPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents) { +// Encodes nevents worth of data from the given port into the given buffer. The +// format of the buffer is precisely that which will be sent to the MOTU. +// The basic idea: +// iterate over the ports +// * get port buffer address +// * loop over events +// - pick right sample in event based upon PortInfo +// - convert sample from Port format (E_Int24, E_Float, ..) to MOTU +// native format +// +// We include the ability to start the transfer from the given offset within +// the port (expressed in frames) so the 'efficient' transfer method can be +// utilised. + + unsigned int j=0; + + // Use char here since the target address won't necessarily be + // aligned; use of an unaligned quadlet_t may cause issues on certain + // architectures. Besides, the target (data going directly to the MOTU) + // isn't structured in quadlets anyway; it mainly consists of packed + // 24-bit integers. + unsigned char *target; + target = (unsigned char *)data + p->getPosition(); + + switch(m_StreamProcessorManager.getAudioDataType()) { + default: + case StreamProcessorManager::eADT_Int24: + { + quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); + + assert(nevents + offset <= p->getBufferSize()); + + // Offset is in frames, but each port is only a single + // channel, so the number of frames is the same as the + // number of quadlets to offset (assuming the port buffer + // uses one quadlet per sample, which is the case currently). + buffer+=offset; + + for(j = 0; j < nevents; j += 1) { // Decode nsamples + *target = (*buffer >> 16) & 0xff; + *(target+1) = (*buffer >> 8) & 0xff; + *(target+2) = (*buffer) & 0xff; + + buffer++; + target+=m_event_size; + } + } + break; + case StreamProcessorManager::eADT_Float: + { + const float multiplier = (float)(0x7FFFFF); + float *buffer=(float *)(p->getBufferAddress()); + + assert(nevents + offset <= p->getBufferSize()); + + buffer+=offset; + + for(j = 0; j < nevents; j += 1) { // decode max nsamples + float in = *buffer; +#if MOTU_CLIP_FLOATS + if (unlikely(in > 1.0)) in = 1.0; + if (unlikely(in < -1.0)) in = -1.0; +#endif + unsigned int v = lrintf(in * multiplier); + *target = (v >> 16) & 0xff; + *(target+1) = (v >> 8) & 0xff; + *(target+2) = v & 0xff; + + buffer++; + target+=m_event_size; + } + } + break; + } + + return 0; +} + +int MotuTransmitStreamProcessor::encodeSilencePortToMotuEvents(MotuAudioPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents) { + unsigned int j=0; + unsigned char *target = (unsigned char *)data + p->getPosition(); + + switch (m_StreamProcessorManager.getAudioDataType()) { + default: + case StreamProcessorManager::eADT_Int24: + case StreamProcessorManager::eADT_Float: + for (j = 0; j < nevents; j++) { + *target = *(target+1) = *(target+2) = 0; + target += m_event_size; + } + break; + } + + return 0; +} + +int MotuTransmitStreamProcessor::encodePortToMotuMidiEvents( + MotuMidiPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents) { + + unsigned int j; + quadlet_t *src = (quadlet_t *)p->getBufferAddress(); + src += offset; + unsigned char *target = (unsigned char *)data + p->getPosition(); + + // Send a MIDI byte if there is one to send. MOTU MIDI data is sent using + // a 3-byte sequence within a frame starting at the port's position. + // A non-zero MSB indicates there is MIDI data to send. + + for (j=0; jgetPosition(); + + // For now, a "silent" MIDI event contains nothing but zeroes. This + // may have to change if we find this isn't for some reason appropriate. + for (j=0; j. + * + */ + +#include "config.h" +#include "libutil/float_cast.h" + +#include "MotuReceiveStreamProcessor.h" +#include "MotuPort.h" +#include "../StreamProcessorManager.h" +#include "devicemanager.h" + +#include "libieee1394/ieee1394service.h" +#include "libieee1394/IsoHandlerManager.h" +#include "libieee1394/cycletimer.h" + +#include "libutil/ByteSwap.h" + +#include +#include +#include + +/* Provide more intuitive access to GCC's branch predition built-ins */ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + + +namespace Streaming { + +// A macro to extract specific bits from a native endian quadlet +#define get_bits(_d,_start,_len) (((_d)>>((_start)-(_len)+1)) & ((1<<(_len))-1)) + +// Convert an SPH timestamp as received from the MOTU to a full timestamp in ticks. +static inline uint32_t sphRecvToFullTicks(uint32_t sph, uint32_t ct_now) { + +uint32_t timestamp = CYCLE_TIMER_TO_TICKS(sph & 0x1ffffff); +uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(ct_now); + +uint32_t ts_sec = CYCLE_TIMER_GET_SECS(ct_now); + // If the cycles have wrapped, correct ts_sec so it represents when timestamp + // was received. The timestamps sent by the MOTU are always 1 or two cycles + // in advance of the cycle timer (reasons unknown at this stage). In addition, + // iso buffering can delay the arrival of packets for quite a number of cycles + // (have seen a delay >12 cycles). + // Every so often we also see sph wrapping ahead of ct_now, so deal with that + // too. + if (unlikely(CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000)) { + if (likely(ts_sec)) + ts_sec--; + else + ts_sec = 127; + } else + if (unlikely(now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000)) { + if (unlikely(ts_sec == 127)) + ts_sec = 0; + else + ts_sec++; + } + return timestamp + ts_sec*TICKS_PER_SECOND; +} + +MotuReceiveStreamProcessor::MotuReceiveStreamProcessor(FFADODevice &parent, unsigned int event_size) + : StreamProcessor(parent, ePT_Receive) + , m_event_size( event_size ) + , mb_head ( 0 ) + , mb_tail ( 0 ) +{ + memset(&m_devctrls, 0, sizeof(m_devctrls)); +} + +unsigned int +MotuReceiveStreamProcessor::getMaxPacketSize() { + int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate(); + return framerate<=48000?616:(framerate<=96000?1032:1160); +} + +unsigned int +MotuReceiveStreamProcessor::getNominalFramesPerPacket() { + int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate(); + return framerate<=48000?8:(framerate<=96000?16:32); +} + +bool +MotuReceiveStreamProcessor::prepareChild() { + debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this); + return true; +} + + +/** + * Processes packet header to extract timestamps and check if the packet is valid + * @param data + * @param length + * @param channel + * @param tag + * @param sy + * @param cycle + * @return + */ +enum StreamProcessor::eChildReturnValue +MotuReceiveStreamProcessor::processPacketHeader(unsigned char *data, unsigned int length, + unsigned char tag, unsigned char sy, + uint32_t pkt_ctr) +{ + if (length > 8) { + // The iso data blocks from the MOTUs comprise a CIP-like + // header followed by a number of events (8 for 1x rates, 16 + // for 2x rates, 32 for 4x rates). + quadlet_t *quadlet = (quadlet_t *)data; + unsigned int dbs = get_bits(CondSwapFromBus32(quadlet[0]), 23, 8); // Size of one event in terms of fdf_size + unsigned int fdf_size = get_bits(CondSwapFromBus32(quadlet[1]), 23, 8) == 0x22 ? 32:0; // Event unit size in bits + + // Don't even attempt to process a packet if it isn't what we expect + // from a MOTU. Yes, an FDF value of 32 bears little relationship + // to the actual data (24 bit integer) sent by the MOTU - it's one + // of those areas where MOTU have taken a curious detour around the + // standards. Do this check early on because for invalid packets + // dbs may not be what we expect, potentially causing issues later + // on. + if (tag!=1 || fdf_size!=32 || dbs==0) { + return eCRV_Invalid; + } + + // m_event_size is the event size in bytes + unsigned int n_events = (length-8) / m_event_size; + + // Acquire the timestamp of the last frame in the packet just + // received. Since every frame from the MOTU has its own timestamp + // we can just pick it straight from the packet. + uint32_t last_sph = CondSwapFromBus32(*(quadlet_t *)(data+8+(n_events-1)*m_event_size)); + m_last_timestamp = sphRecvToFullTicks(last_sph, m_Parent.get1394Service().getCycleTimer()); + + return eCRV_OK; + } else { + return eCRV_Invalid; + } +} + +/** + * extract the data from the packet + * @pre the IEC61883 packet is valid according to isValidPacket + * @param data + * @param length + * @param channel + * @param tag + * @param sy + * @param pkt_ctr + * @return + */ +enum StreamProcessor::eChildReturnValue +MotuReceiveStreamProcessor::processPacketData(unsigned char *data, unsigned int length) { + // m_event_size should never be zero + unsigned int n_events = (length-8) / m_event_size; + + // we have to keep in mind that there are also + // some packets buffered by the ISO layer, + // at most x=m_handler->getWakeupInterval() + // these contain at most x*syt_interval + // frames, meaning that we might receive + // this packet x*syt_interval*ticks_per_frame + // later than expected (the real receive time) + #ifdef DEBUG + if(isRunning()) { + debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"STMP: %lluticks | tpf=%f\n", + m_last_timestamp, getTicksPerFrame()); + } + #endif + + if(m_data_buffer->writeFrames(n_events, (char *)(data+8), m_last_timestamp)) { + return eCRV_OK; + } else { + return eCRV_XRun; + } +} + +/*********************************************** + * Encoding/Decoding API * + ***********************************************/ +/** + * \brief write received events to the port ringbuffers. + */ +bool MotuReceiveStreamProcessor::processReadBlock(char *data, + unsigned int nevents, unsigned int offset) +{ + bool no_problem=true; + + /* Scan incoming block for device control events */ + decodeMotuCtrlEvents(data, nevents); + + for ( PortVectorIterator it = m_Ports.begin(); + it != m_Ports.end(); + ++it ) { + if((*it)->isDisabled()) {continue;}; + + Port *port=(*it); + + switch(port->getPortType()) { + + case Port::E_Audio: + if(decodeMotuEventsToPort(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not decode packet data to port %s\n",(*it)->getName().c_str()); + no_problem=false; + } + break; + case Port::E_Midi: + if(decodeMotuMidiEventsToPort(static_cast(*it), (quadlet_t *)data, offset, nevents)) { + debugWarning("Could not decode packet midi data to port %s\n",(*it)->getName().c_str()); + no_problem=false; + } + break; + + default: // ignore + break; + } + } + return no_problem; +} + +signed int MotuReceiveStreamProcessor::decodeMotuEventsToPort(MotuAudioPort *p, + quadlet_t *data, unsigned int offset, unsigned int nevents) +{ + unsigned int j=0; + + // Use char here since a port's source address won't necessarily be + // aligned; use of an unaligned quadlet_t may cause issues on + // certain architectures. Besides, the source (data coming directly + // from the MOTU) isn't structured in quadlets anyway; it mainly + // consists of packed 24-bit integers. + + unsigned char *src_data; + src_data = (unsigned char *)data + p->getPosition(); + + switch(m_StreamProcessorManager.getAudioDataType()) { + default: + case StreamProcessorManager::eADT_Int24: + { + quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress()); + + assert(nevents + offset <= p->getBufferSize()); + + // Offset is in frames, but each port is only a single + // channel, so the number of frames is the same as the + // number of quadlets to offset (assuming the port buffer + // uses one quadlet per sample, which is the case currently). + buffer+=offset; + + for(j = 0; j < nevents; j += 1) { // Decode nsamples + *buffer = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2); + // Sign-extend highest bit of 24-bit int. + // This isn't strictly needed since E_Int24 is a 24-bit, + // but doing so shouldn't break anything and makes the data + // easier to deal with during debugging. + if (*src_data & 0x80) + *buffer |= 0xff000000; + + buffer++; + src_data+=m_event_size; + } + } + break; + case StreamProcessorManager::eADT_Float: + { + const float multiplier = 1.0f / (float)(0x7FFFFF); + float *buffer=(float *)(p->getBufferAddress()); + + assert(nevents + offset <= p->getBufferSize()); + + buffer+=offset; + + for(j = 0; j < nevents; j += 1) { // decode max nsamples + + signed int v = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2); + /* Sign-extend highest bit of incoming 24-bit integer */ + if (*src_data & 0x80) + v |= 0xff000000; + *buffer = v * multiplier; + buffer++; + src_data+=m_event_size; + } + } + break; + } + + return 0; +} + +int +MotuReceiveStreamProcessor::decodeMotuMidiEventsToPort( + MotuMidiPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents) +{ + unsigned int j = 0; + unsigned char *src = NULL; + + quadlet_t *buffer = (quadlet_t *)(p->getBufferAddress()); + assert(nevents + offset <= p->getBufferSize()); + buffer += offset; + + // Zero the buffer + memset(buffer, 0, nevents*sizeof(*buffer)); + + // Get MIDI bytes if present in any frames within the packet. MOTU MIDI + // data is sent as part of a 3-byte sequence starting at the port's + // position. Some MOTUs (eg: the 828MkII) send more than one MIDI byte + // in some packets. Since the FFADO MIDI layer requires a MIDI byte in + // only every 8th buffer position we allow for this by buffering the + // incoming data. The buffer is small since it only has to cover for + // short-term excursions in the data rate. Since the MIDI data + // originates on a physical MIDI bus the overall data rate is limited by + // the baud rate of that bus (31250), which is no more than one byte in + // 8 even for 1x sample rates. + src = (unsigned char *)data + p->getPosition(); + // We assume that the buffer has been set up in such a way that the first + // element is correctly aligned for FFADOs MIDI layer. The requirement + // is that actual MIDI bytes must be aligned to multiples of 8 samples. + + while (j < nevents) { + /* Most events don't have MIDI data bytes */ + if (unlikely((*src & MOTU_KEY_MASK_MIDI) == MOTU_KEY_MASK_MIDI)) { + // A MIDI byte is in *(src+2). Bit 24 is used to flag MIDI data + // as present once the data makes it to the output buffer. + midibuffer[mb_head++] = 0x01000000 | *(src+2); + mb_head &= RX_MIDIBUFFER_SIZE-1; + if (unlikely(mb_head == mb_tail)) { + debugWarning("MOTU rx MIDI buffer overflow\n"); + /* Dump oldest byte. This overflow can only happen if the + * rate coming in from the hardware MIDI port grossly + * exceeds the official MIDI baud rate of 31250 bps, so it + * should never occur in practice. + */ + mb_tail = (mb_tail + 1) & (RX_MIDIBUFFER_SIZE-1); + } + } + /* Write to the buffer if we're at an 8-sample boundary */ + if (unlikely(!(j & 0x07))) { + if (mb_head != mb_tail) { + *buffer = midibuffer[mb_tail++]; + mb_tail &= RX_MIDIBUFFER_SIZE-1; + } + buffer += 8; + } + j++; + src += m_event_size; + } + + return 0; +} + +int +MotuReceiveStreamProcessor::decodeMotuCtrlEvents( + char *data, unsigned int nevents) +{ + unsigned int j = 0; + unsigned char *src = NULL; + unsigned char *arg = NULL; + + // Get control bytes if present in any frames within the packet. The + // device control messages start at (zero-based) byte 0x04 in the data + // stream. + src = (unsigned char *)data + 0x04; + arg = src+1; + while (j < nevents) { + unsigned int control_key = *src & ~MOTU_KEY_MASK_MIDI; + + if (m_devctrls.status == MOTU_DEVCTRL_INVALID) { + // Start syncing on reception of the sequence sync key which indicates + // mix bus 1 values are pending. Acquisition will start when we see the + // first channel gain key after this. + if (control_key==MOTU_KEY_SEQ_SYNC && *arg==MOTU_KEY_SEQ_SYNC_MIXBUS1) { + debugOutput(DEBUG_LEVEL_VERBOSE, "syncing device control status stream\n"); + m_devctrls.status = MOTU_DEVCTRL_SYNCING; + } + } else + if (m_devctrls.status == MOTU_DEVCTRL_SYNCING) { + // Start acquiring when we see a channel gain key for mixbus 1. + if (control_key == MOTU_KEY_SEQ_SYNC) { + // Keep mixbus index updated since we don't execute the main parser until + // we move to the initialising state. Since we don't dereference this until + // we know it's equal to 0 there's no need for bounds checking here. + m_devctrls.mixbus_index = *arg; + } else + if (control_key==MOTU_KEY_CHANNEL_GAIN && m_devctrls.mixbus_index==0) { + debugOutput(DEBUG_LEVEL_VERBOSE, "initialising device control status\n"); + m_devctrls.status = MOTU_DEVCTRL_INIT; + } + } else + if (m_devctrls.status == MOTU_DEVCTRL_INIT) { + // Consider ourselves fully initialised when a control sequence sync key + // arrives which takes things back to mixbus 1. + if (control_key==MOTU_KEY_SEQ_SYNC && *arg==MOTU_KEY_SEQ_SYNC_MIXBUS1 && m_devctrls.mixbus_index>0) { + debugOutput(DEBUG_LEVEL_VERBOSE, "device control status valid: n_mixbuses=%d, n_channels=%d\n", + m_devctrls.n_mixbuses, m_devctrls.n_channels); + m_devctrls.status = MOTU_DEVCTRL_VALID; + } + } + + if (m_devctrls.status==MOTU_DEVCTRL_INIT || m_devctrls.status==MOTU_DEVCTRL_VALID) { + unsigned int i; + switch (control_key) { + case MOTU_KEY_SEQ_SYNC: + if (m_devctrls.mixbus_index < MOTUFW_MAX_MIXBUSES) { + if (m_devctrls.n_channels==0 && m_devctrls.mixbus[m_devctrls.mixbus_index].channel_gain_index!=0) { + m_devctrls.n_channels = m_devctrls.mixbus[m_devctrls.mixbus_index].channel_gain_index; + } + } + /* Mix bus to configure next is in bits 5-7 of the argument */ + m_devctrls.mixbus_index = (*arg >> 5); + if (m_devctrls.mixbus_index >= MOTUFW_MAX_MIXBUSES) { + debugWarning("MOTU cuemix value parser error: mix bus index %d exceeded maximum %d\n", + m_devctrls.mixbus_index, MOTUFW_MAX_MIXBUSES); + } else { + if (m_devctrls.n_mixbuses < m_devctrls.mixbus_index+1) { + m_devctrls.n_mixbuses = m_devctrls.mixbus_index+1; + } + m_devctrls.mixbus[m_devctrls.mixbus_index].channel_gain_index = + m_devctrls.mixbus[m_devctrls.mixbus_index].channel_pan_index = + m_devctrls.mixbus[m_devctrls.mixbus_index].channel_control_index = 0; + } + break; + case MOTU_KEY_CHANNEL_GAIN: + i = m_devctrls.mixbus[m_devctrls.mixbus_index].channel_gain_index++; + if (m_devctrls.mixbus_index= MOTUFW_MAX_MIXBUS_CHANNELS) { + debugWarning("MOTU cuemix value parser error: channel gain index %d exceeded maximum %d\n", + i, MOTUFW_MAX_MIXBUS_CHANNELS); + } + break; + case MOTU_KEY_CHANNEL_PAN: + i = m_devctrls.mixbus[m_devctrls.mixbus_index].channel_pan_index++; + if (m_devctrls.mixbus_index= MOTUFW_MAX_MIXBUS_CHANNELS) { + debugWarning("MOTU cuemix value parser error: channel pan index %d exceeded maximum %d\n", + i, MOTUFW_MAX_MIXBUS_CHANNELS); + } + break; + case MOTU_KEY_CHANNEL_CTRL: + i = m_devctrls.mixbus[m_devctrls.mixbus_index].channel_control_index++; + if (m_devctrls.mixbus_index= MOTUFW_MAX_MIXBUS_CHANNELS) { + debugWarning("MOTU cuemix value parser error: channel control index %d exceeded maximum %d\n", + i, MOTUFW_MAX_MIXBUS_CHANNELS); + } + break; + case MOTU_KEY_MIXBUS_GAIN: + if (m_devctrls.mixbus_index < MOTUFW_MAX_MIXBUSES) { + m_devctrls.mixbus[m_devctrls.mixbus_index].bus_gain = *arg; + } + break; + case MOTU_KEY_MIXBUS_DEST: + if (m_devctrls.mixbus_index < MOTUFW_MAX_MIXBUSES) { + m_devctrls.mixbus[m_devctrls.mixbus_index].bus_dest = *arg; + } + break; + case MOTU_KEY_MAINOUT_VOL: + m_devctrls.main_out_volume = *arg; + break; + case MOTU_KEY_PHONES_VOL: + m_devctrls.phones_volume = *arg; + break; + case MOTU_KEY_PHONES_DEST: + m_devctrls.phones_assign = *arg; + break; + case MOTU_KEY_INPUT_6dB_BOOST: + m_devctrls.input_6dB_boost = *arg; + break; + case MOTU_KEY_INPUT_REF_LEVEL: + m_devctrls.input_ref_level = *arg; + break; + case MOTU_KEY_MIDI: + // MIDI is dealt with elsewhere, so just pass it over + break; + default: + // Ignore any unknown keys or those we don't care about, at + // least for now. + break; + } + } + j++; + src += m_event_size; + arg += m_event_size; + } + + return 0; +} + +} // end of namespace Streaming Index: /tags/2.0-rc2/src/libstreaming/motu/MotuPortInfo.cpp =================================================================== --- /tags/2.0-rc2/src/libstreaming/motu/MotuPortInfo.cpp (revision 864) +++ /tags/2.0-rc2/src/libstreaming/motu/MotuPortInfo.cpp (revision 864) @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#include "MotuPortInfo.h" + +namespace Streaming { + + +} // end of namespace Streaming Index: /tags/2.0-rc2/src/libstreaming/motu/MotuTransmitStreamProcessor.h =================================================================== --- /tags/2.0-rc2/src/libstreaming/motu/MotuTransmitStreamProcessor.h (revision 1419) +++ /tags/2.0-rc2/src/libstreaming/motu/MotuTransmitStreamProcessor.h (revision 1419) @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#ifndef __FFADO_MOTUTRANSMITSTREAMPROCESSOR__ +#define __FFADO_MOTUTRANSMITSTREAMPROCESSOR__ + +/** + * This class implements MOTU based streaming + */ + +#include "debugmodule/debugmodule.h" + +#include "../generic/StreamProcessor.h" +#include "../util/cip.h" + +namespace Streaming { + +class Port; +class MotuAudioPort; +class MotuMidiPort; +/*! +\brief The Base Class for an MOTU transmit stream processor + + This class implements a TransmitStreamProcessor that multiplexes Ports + into MOTU streams. + +*/ +class MotuTransmitStreamProcessor + : public StreamProcessor +{ + +public: + /** + * Create a MOTU transmit StreamProcessor + */ + MotuTransmitStreamProcessor(FFADODevice &parent, unsigned int event_size); + virtual ~MotuTransmitStreamProcessor() {}; + + enum eChildReturnValue generatePacketHeader(unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr); + enum eChildReturnValue generatePacketData(unsigned char *data, unsigned int *length); + enum eChildReturnValue generateEmptyPacketHeader(unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr); + enum eChildReturnValue generateEmptyPacketData(unsigned char *data, unsigned int *length); + enum eChildReturnValue generateSilentPacketHeader(unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr); + enum eChildReturnValue generateSilentPacketData(unsigned char *data, unsigned int *length); + virtual bool prepareChild(); + +public: + virtual unsigned int getEventSize() + {return m_event_size;}; + virtual unsigned int getMaxPacketSize(); + virtual unsigned int getEventsPerFrame() + { return 1; }; + virtual unsigned int getNominalFramesPerPacket(); + +protected: + bool processWriteBlock(char *data, unsigned int nevents, unsigned int offset); + bool transmitSilenceBlock(char *data, unsigned int nevents, unsigned int offset); + +private: + unsigned int fillNoDataPacketHeader(quadlet_t *data, unsigned int* length); + unsigned int fillDataPacketHeader(quadlet_t *data, unsigned int* length, uint32_t ts); + + int transmitBlock(char *data, unsigned int nevents, + unsigned int offset); + + bool encodePacketPorts(quadlet_t *data, unsigned int nevents, + unsigned int dbc); + + int encodePortToMotuEvents(MotuAudioPort *, quadlet_t *data, + unsigned int offset, unsigned int nevents); + int encodeSilencePortToMotuEvents(MotuAudioPort *, quadlet_t *data, + unsigned int offset, unsigned int nevents); + + int encodePortToMotuMidiEvents( + MotuMidiPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents); + int encodeSilencePortToMotuMidiEvents( + MotuMidiPort *p, quadlet_t *data, + unsigned int offset, unsigned int nevents); + + /* + * An iso packet mostly consists of multiple events. m_event_size + * is the size of a single 'event' in bytes. + */ + unsigned int m_event_size; + + // Keep track of transmission data block count + unsigned int m_tx_dbc; + + // A simple circular buffer for outgoing MIDI data to allow + // a rate control to be implemented on the data to suit the MOTU + // devices. Note that this buffer's size is forced to be a power + // of 2 to allow for buffer manipulation optimisations. + #define MIDIBUFFER_SIZE_EXP 10 + #define MIDIBUFFER_SIZE (1<. + * + */ + +#ifndef __FFADO_MOTURECEIVESTREAMPROCESSOR__ +#define __FFADO_MOTURECEIVESTREAMPROCESSOR__ + +/** + * This class implements MOTU streaming + */ + +#include "debugmodule/debugmodule.h" + +#include "../generic/StreamProcessor.h" +#include "../util/cip.h" + +namespace Streaming { + +#define MOTUFW_MAX_MIXBUSES 4 +#define MOTUFW_MAX_MIXBUS_CHANNELS 20 + +#define MOTU_CHANNEL_NORMAL 0x00 +#define MOTU_CHANNEL_MUTE 0x01 +#define MOTU_CHANNEL_SOLO 0x02 +#define MOTU_CHANNEL_PAIRED 0x08 + +#define MOTU_CHANNEL_PAN_LEFT 0x00 +#define MOTU_CHANNEL_PAN_RIGHT 0x80 +#define MOTU_CHANNEL_PAN_CENTRE 0x40 + +#define MOTU_DEST_DISABLED 0x00 +#define MOTU_DEST_HEADPHONE 0x01 +#define MOTU_DEST_ANALOG1_2 0x02 +#define MOTU_DEST_ANALOG3_4 0x03 +#define MOTU_DEST_ANALOG5_6 0x04 +#define MOTU_DEST_ANALOG7_8 0x05 +#define MOTU_DEST_AESEBU 0x06 +#define MOTU_DEST_SPDIF 0x07 +#define MOTU_DEST_ADAT1_1_2 0x08 +#define MOTU_DEST_ADAT1_3_4 0x09 +#define MOTU_DEST_ADAT1_5_6 0x0a +#define MOTU_DEST_ADAT1_7_8 0x0b +#define MOTU_DEST_MUTE 0x10 + +enum EMotuDevCtrlStatus { + MOTU_DEVCTRL_INVALID = 0x00, + MOTU_DEVCTRL_SYNCING = 0x01, + MOTU_DEVCTRL_INIT = 0x02, + MOTU_DEVCTRL_VALID = 0x03, +}; + +struct MotuDevControls { + unsigned int status; + unsigned int input_6dB_boost; + unsigned int input_ref_level; + unsigned int input_20dB_pad; + unsigned int input_gaintrim[MOTUFW_MAX_MIXBUS_CHANNELS]; + unsigned char input_gaintrim_index; + struct MixBus { + unsigned char channel_gain[MOTUFW_MAX_MIXBUS_CHANNELS]; + unsigned char channel_gain_index; + unsigned char channel_pan[MOTUFW_MAX_MIXBUS_CHANNELS]; + unsigned char channel_pan_index; + unsigned char channel_control[MOTUFW_MAX_MIXBUS_CHANNELS]; + unsigned char channel_control_index; + unsigned char bus_gain; + unsigned char bus_dest; + } mixbus[MOTUFW_MAX_MIXBUSES]; + unsigned char mixbus_index; + unsigned char main_out_volume; + unsigned char phones_volume; + unsigned char phones_assign; + unsigned char n_mixbuses; + unsigned char n_channels; +}; + +enum EMotuCtrlKeys { + MOTU_KEY_MIDI = 0x01, + MOTU_KEY_SEQ_SYNC = 0x0c, + MOTU_KEY_CHANNEL_GAIN = 0x14, + MOTU_KEY_CHANNEL_PAN = 0x1c, + MOTU_KEY_CHANNEL_CTRL = 0x24, + MOTU_KEY_MIXBUS_GAIN = 0x2c, + MOTU_KEY_MIXBUS_DEST = 0x34, + MOTU_KEY_MAINOUT_VOL = 0x3c, + MOTU_KEY_PHONES_VOL = 0x44, + MOTU_KEY_PHONES_DEST = 0x4c, + MOTU_KEY_INPUT_6dB_BOOST = 0x6c, + MOTU_KEY_INPUT_REF_LEVEL = 0x74, + MOTU_KEY_MASK_MIDI = 0x01, +}; + +enum EMotuSeqSyncMixbuses { + MOTU_KEY_SEQ_SYNC_MIXBUS1 = 0x00, + MOTU_KEY_SEQ_SYNC_MIXBUS2 = 0x20, + MOTU_KEY_SEQ_SYNC_MIXBUS3 = 0x40, + MOTU_KEY_SEQ_SYNC_MIXBUS4 = 0x60, +}; + +class MotuAudioPort; +class MotuMidiPort; +/*! + * \brief The Base Class for a MOTU receive stream processor + * + * This class implements the outgoing stream processing for + * motu devices + * + */ +class MotuReceiveStreamProcessor + : public StreamProcessor +{ + +public: + /** + * Create a MOTU receive StreamProcessor + * @param port 1394 port + * @param dimension number of substreams in the ISO stream + * (midi-muxed is only one stream) + */ + MotuReceiveStreamProcessor(FFADODevice &parent, unsigned int event_size); + virtual ~MotuReceiveStreamProcessor() {}; + + enum eChildReturnValue processPacketHeader(unsigned char *data, unsigned int length, + unsigned char tag, unsigned char sy, + uint32_t pkt_ctr); + enum eChildReturnValue processPacketData(unsigned char *data, unsigned int length); + + virtual bool prepareChild(); + +public: + virtual unsigned int getEventSize() + {return m_event_size;}; + virtual unsigned int getMaxPacketSize(); + virtual unsigned int getEventsPerFrame() + { return 1; }; + virtual unsigned int getNominalFramesPerPacket(); + +protected: + bool processReadBlock(char *data, unsigned int nevents, unsigned int offset); + +private: + bool decodePacketPorts(quadlet_t *data, unsigned int nevents, unsigned int dbc); + + int decodeMotuEventsToPort(MotuAudioPort *, quadlet_t *data, unsigned int offset, unsigned int nevents); + int decodeMotuMidiEventsToPort(MotuMidiPort *, quadlet_t *data, unsigned int offset, unsigned int nevents); + int decodeMotuCtrlEvents(char *data, unsigned int nevents); + + /* + * An iso packet mostly consists of multiple events. m_event_size + * is the size of a single 'event' in bytes. + */ + unsigned int m_event_size; + + struct MotuDevControls m_devctrls; + + /* A small MIDI buffer to cover for the case where we need to span a + * period. This can only occur if more than one MIDI byte is sent per + * packet, but this has been observed with some MOTUs (eg: 828MkII). + * Since the long-term average data rate must be close to the MIDI spec + * since it's coming from a physical MIDI port this buffer doesn't have + * to be particularly large. The size is a power of 2 for optimisation + * reasons. + */ + #define RX_MIDIBUFFER_SIZE_EXP 6 + #define RX_MIDIBUFFER_SIZE (1<. + * + */ + +#include "MotuPort.h" +#include + +namespace Streaming { + +} // end of namespace Streaming Index: /tags/2.0-rc2/src/libstreaming/motu/MotuPortInfo.h =================================================================== --- /tags/2.0-rc2/src/libstreaming/motu/MotuPortInfo.h (revision 864) +++ /tags/2.0-rc2/src/libstreaming/motu/MotuPortInfo.h (revision 864) @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2005-2008 by Jonathan Woithe + * 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 . + * + */ + +#ifndef __FFADO_MOTUPORTINFO__ +#define __FFADO_MOTUPORTINFO__ + +#include "debugmodule/debugmodule.h" +#include + +namespace Streaming { +/*! +\brief Class containing the stream information for a Motu channel + + Contains the information that enables the decoding routine to find + this port's data in the ISO events + +*/ +class MotuPortInfo { + +public: + /** + * Sometimes a channel can have multiple formats, depending on the + * device configuration (e.g. an SPDIF port could be plain audio in 24bit integer + * or AC3 passthrough in IEC compliant frames.) + * + * This kind of enum allows to discriminate these formats when decoding + * If all channels always have the same format, you won't be needing this + */ +// enum E_Formats { +// E_MBLA, // Multibit linear audio +// E_Midi, // MIDI +// }; + + /** + * Initialize Motu portinfo + * should not be called directly, is inherited by motu ports + * + * the position parameter is an example + * the name parameter is mandatory + * + * @param position Start position of port's data in iso event + * @param format Format of data in iso event + * @param size Size in bits of port's data in iso event + * @return + */ + MotuPortInfo( int position, int size) + : m_position(position), m_size(size) + {}; + virtual ~MotuPortInfo() {}; + + + int getPosition() {return m_position;}; + int getSize() {return m_size;}; + +protected: + + int m_position; + int m_size; + +}; + +} // end of namespace Streaming + +#endif /* __FFADO_MOTUPORTINFO__ */ Index: /tags/2.0-rc2/src/libstreaming/amdtp/AmdtpPort.h =================================================================== --- /tags/2.0-rc2/src/libstreaming/amdtp/AmdtpPort.h (revision 864) +++ /tags/2.0-rc2/src/libstreaming/amdtp/AmdtpPort.h (revision 864) @@ -0,0 +1,89 @@ +/* + * 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 . + * + */ + +#ifndef __FFADO_AMDTPPORT__ +#define __FFADO_AMDTPPORT__ + +/** + * This file implements the AMDTP ports as used in the BeBoB's + */ + +#include "debugmodule/debugmodule.h" +#include "../generic/Port.h" +#include "AmdtpPortInfo.h" + +namespace Streaming { + +/*! +\brief The Base Class for an AMDTP Audio Port + + The AMDTP/AM824/IEC61883-6 port that represents audio. + +*/ +class AmdtpAudioPort + : public AudioPort, public AmdtpPortInfo +{ + +public: + + AmdtpAudioPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position, + int location, + enum E_Formats format) + : AudioPort(m, name, direction), + AmdtpPortInfo(position, location, format) + {}; + + virtual ~AmdtpAudioPort() {}; +}; + +/*! +\brief The Base Class for an AMDTP Midi Port + + The AMDTP/AM824/IEC61883-6 port that represents midi. + +*/ +class AmdtpMidiPort + : public MidiPort, public AmdtpPortInfo +{ + +public: + + AmdtpMidiPort(PortManager &m, + std::string name, + enum E_Direction direction, + int position, + int location, + enum E_Formats format) + : MidiPort(m, name, direction), + AmdtpPortInfo(position, location, format) + {}; + + virtual ~AmdtpMidiPort() {}; +}; + +} // end of namespace Streaming + +#endif /* __FFADO_AMDTPPORT__ */ Index: /tags/2.0-rc2/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp =================================================================== --- /tags/2.0-rc2/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp (revision 1546) +++ /tags/2.0-rc2/src/libstreaming/amdtp/AmdtpTransmitStreamProcessor.cpp (revision 1546) @@ -0,0 +1,1195 @@ +/* + * 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 . + * + */ + +#include "config.h" +#include "AmdtpTransmitStreamProcessor.h" +#include "AmdtpPort.h" +#include "../StreamProcessorManager.h" +#include "devicemanager.h" + +#include "libutil/Time.h" +#include "libutil/float_cast.h" + +#include "libieee1394/ieee1394service.h" +#include "libieee1394/IsoHandlerManager.h" +#include "libieee1394/cycletimer.h" + +#include "libutil/ByteSwap.h" +#include +#include + +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +#define AMDTP_FLOAT_MULTIPLIER (1.0f * ((1<<23) - 1)) +namespace Streaming +{ + +/* transmit */ +AmdtpTransmitStreamProcessor::AmdtpTransmitStreamProcessor(FFADODevice &parent, int dimension) + : StreamProcessor(parent, ePT_Transmit) + , m_dimension( dimension ) + , m_dbc( 0 ) +#if AMDTP_ALLOW_PAYLOAD_IN_NODATA_XMIT + , m_send_nodata_payload ( AMDTP_SEND_PAYLOAD_IN_NODATA_XMIT_BY_DEFAULT ) +#endif + , m_max_cycles_to_transmit_early ( AMDTP_MAX_CYCLES_TO_TRANSMIT_EARLY ) + , m_transmit_transfer_delay ( AMDTP_TRANSMIT_TRANSFER_DELAY ) + , m_min_cycles_before_presentation ( AMDTP_MIN_CYCLES_BEFORE_PRESENTATION ) + , m_nb_audio_ports( 0 ) + , m_nb_midi_ports( 0 ) +{} + +enum StreamProcessor::eChildReturnValue +AmdtpTransmitStreamProcessor::generatePacketHeader ( + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr ) +{ + __builtin_prefetch(data, 1, 0); // prefetch events for write, no temporal locality + struct iec61883_packet *packet = (struct iec61883_packet *)data; + /* Our node ID can change after a bus reset, so it is best to fetch + * our node ID for each packet. */ + packet->sid = m_local_node_id; + + packet->dbs = m_dimension; + packet->fn = 0; + packet->qpc = 0; + packet->sph = 0; + packet->reserved = 0; + packet->dbc = m_dbc; + packet->eoh1 = 2; + packet->fmt = IEC61883_FMT_AMDTP; + + *tag = IEC61883_TAG_WITH_CIP; + *sy = 0; + + signed int fc; + uint64_t presentation_time; + unsigned int presentation_cycle; + int cycles_until_presentation; + + uint64_t transmit_at_time; + unsigned int transmit_at_cycle; + int cycles_until_transmit; + + debugOutputExtreme( DEBUG_LEVEL_ULTRA_VERBOSE, + "Try for cycle %d\n", CYCLE_TIMER_GET_CYCLES(pkt_ctr) ); + // check whether the packet buffer has packets for us to send. + // the base timestamp is the one of the next sample in the buffer + ffado_timestamp_t ts_head_tmp; + m_data_buffer->getBufferHeadTimestamp( &ts_head_tmp, &fc ); // thread safe + + // the timestamp gives us the time at which we want the sample block + // to be output by the device + presentation_time = ( uint64_t ) ts_head_tmp; + + // now we calculate the time when we have to transmit the sample block + transmit_at_time = substractTicks( presentation_time, m_transmit_transfer_delay ); + + // calculate the cycle this block should be presented in + // (this is just a virtual calculation since at that time it should + // already be in the device's buffer) + presentation_cycle = ( unsigned int ) ( TICKS_TO_CYCLES ( presentation_time ) ); + + // calculate the cycle this block should be transmitted in + transmit_at_cycle = ( unsigned int ) ( TICKS_TO_CYCLES ( transmit_at_time ) ); + + // we can check whether this cycle is within the 'window' we have + // to send this packet. + // first calculate the number of cycles left before presentation time + cycles_until_presentation = diffCycles ( presentation_cycle, CYCLE_TIMER_GET_CYCLES(pkt_ctr) ); + + // we can check whether this cycle is within the 'window' we have + // to send this packet. + // first calculate the number of cycles left before presentation time + cycles_until_transmit = diffCycles ( transmit_at_cycle, CYCLE_TIMER_GET_CYCLES(pkt_ctr) ); + + // two different options: + // 1) there are not enough frames for one packet + // => determine wether this is a problem, since we might still + // have some time to send it + // 2) there are enough packets + // => determine whether we have to send them in this packet + if ( fc < ( signed int ) m_syt_interval ) + { + // not enough frames in the buffer, + + // we can still postpone the queueing of the packets + // if we are far enough ahead of the presentation time + if ( cycles_until_presentation <= m_min_cycles_before_presentation ) + { + debugOutput( DEBUG_LEVEL_NORMAL, + "Insufficient frames (P): N=%02d, CY=%04u, TC=%04u, CUT=%04d\n", + fc, CYCLE_TIMER_GET_CYCLES(pkt_ctr), + transmit_at_cycle, cycles_until_transmit ); + // we are too late + return eCRV_XRun; + } + else + { + #if DEBUG_EXTREME + unsigned int now_cycle = ( unsigned int ) ( TICKS_TO_CYCLES ( m_1394service.getCycleTimerTicks() ) ); + + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "Insufficient frames (NP): N=%02d, CY=%04u, TC=%04u, CUT=%04d, NOW=%04d\n", + fc, CYCLE_TIMER_GET_CYCLES(pkt_ctr), + transmit_at_cycle, cycles_until_transmit, now_cycle ); + #endif + + // there is still time left to send the packet + // we want the system to give this packet another go at a later time instant + return eCRV_Again; // note that the raw1394 again system doesn't work as expected + + // we could wait here for a certain time before trying again. However, this + // is not going to work since we then block the iterator thread, hence also + // the receiving code, meaning that we are not processing received packets, + // and hence there is no progression in the number of frames available. + + // for example: + // SleepRelativeUsec(125); // one cycle + // goto try_block_of_frames; + + // or more advanced, calculate how many cycles we are ahead of 'now' and + // base the sleep on that. + + // note that this requires that there is one thread for each IsoHandler, + // otherwise we're in the deadlock described above. + } + } + else + { + // there are enough frames, so check the time they are intended for + // all frames have a certain 'time window' in which they can be sent + // this corresponds to the range of the timestamp mechanism: + // we can send a packet 15 cycles in advance of the 'presentation time' + // in theory we can send the packet up till one cycle before the presentation time, + // however this is not very smart. + + // There are 3 options: + // 1) the frame block is too early + // => send an empty packet + // 2) the frame block is within the window + // => send it + // 3) the frame block is too late + // => discard (and raise xrun?) + // get next block of frames and repeat + + if(cycles_until_transmit < 0) + { + // we are too late + debugOutput(DEBUG_LEVEL_VERBOSE, + "Too late: CY=%04u, TC=%04u, CUT=%04d, TSP=%011llu (%04u)\n", + CYCLE_TIMER_GET_CYCLES(pkt_ctr), + transmit_at_cycle, cycles_until_transmit, + presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time) ); + //debugShowBackLogLines(200); + // however, if we can send this sufficiently before the presentation + // time, it could be harmless. + // NOTE: dangerous since the device has no way of reporting that it didn't get + // this packet on time. + if(cycles_until_presentation >= m_min_cycles_before_presentation) + { + // we are not that late and can still try to transmit the packet + m_dbc += fillDataPacketHeader(packet, length, presentation_time); + m_last_timestamp = presentation_time; + return (fc < (signed)(2*m_syt_interval) ? eCRV_Defer : eCRV_Packet); + } + else // definitely too late + { + return eCRV_XRun; + } + } + else if(cycles_until_transmit <= m_max_cycles_to_transmit_early) + { + // it's time send the packet + m_dbc += fillDataPacketHeader(packet, length, presentation_time); + m_last_timestamp = presentation_time; + + // for timestamp tracing + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "XMIT PKT: TSP= %011llu (%04u) (%04u) (%04u)\n", + presentation_time, + (unsigned int)CYCLE_TIMER_GET_CYCLES(pkt_ctr), + presentation_cycle, transmit_at_cycle); + + return (fc < (signed)(m_syt_interval) ? eCRV_Defer : eCRV_Packet); + } + else + { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "Too early: CY=%04u, TC=%04u, CUT=%04d, TST=%011llu (%04u), TSP=%011llu (%04u)\n", + CYCLE_TIMER_GET_CYCLES(pkt_ctr), + transmit_at_cycle, cycles_until_transmit, + transmit_at_time, (unsigned int)TICKS_TO_CYCLES(transmit_at_time), + presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time)); +#ifdef DEBUG + if ( cycles_until_transmit > m_max_cycles_to_transmit_early + 1 ) + { + debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, + "Way too early: CY=%04u, TC=%04u, CUT=%04d, TST=%011llu (%04u), TSP=%011llu (%04u)\n", + CYCLE_TIMER_GET_CYCLES(pkt_ctr), + transmit_at_cycle, cycles_until_transmit, + transmit_at_time, (unsigned int)TICKS_TO_CYCLES(transmit_at_time), + presentation_time, (unsigned int)TICKS_TO_CYCLES(presentation_time)); + } +#endif + // we are too early, send only an empty packet + return eCRV_EmptyPacket; + } + } + return eCRV_Invalid; +} + +enum StreamProcessor::eChildReturnValue +AmdtpTransmitStreamProcessor::generatePacketData ( + unsigned char *data, unsigned int *length ) +{ + if (m_data_buffer->readFrames(m_syt_interval, (char *)(data + 8))) + { + debugOutputExtreme(DEBUG_LEVEL_VERBOSE, + "XMIT DATA: TSP= %011llu (%04u)\n", + m_last_timestamp, + (unsigned int)TICKS_TO_CYCLES(m_last_timestamp)); + #if 0 + // debug code to output the packet content + char tmpbuff[8192]; + int cnt=0; + quadlet_t *tmp = (quadlet_t *)((char *)(data + 8)); + + for(int i=0; isid = m_local_node_id; + + packet->dbs = m_dimension; + packet->fn = 0; + packet->qpc = 0; + packet->sph = 0; + packet->reserved = 0; + packet->dbc = m_dbc; + packet->eoh1 = 2; + packet->fmt = IEC61883_FMT_AMDTP; + + *tag = IEC61883_TAG_WITH_CIP; + *sy = 0; + + m_dbc += fillNoDataPacketHeader(packet, length); + return eCRV_Packet; +} + +enum StreamProcessor::eChildReturnValue +AmdtpTransmitStreamProcessor::generateSilentPacketData ( + unsigned char *data, unsigned int *length ) +{ + return eCRV_OK; // no need to do anything +} + +enum StreamProcessor::eChildReturnValue +AmdtpTransmitStreamProcessor::generateEmptyPacketHeader ( + unsigned char *data, unsigned int *length, + unsigned char *tag, unsigned char *sy, + uint32_t pkt_ctr ) +{ + struct iec61883_packet *packet = ( struct iec61883_packet * ) data; + debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, + "XMIT EMPTY (cy %04d): CY=%04u, TSP=%011llu (%04u)\n", + CYCLE_TIMER_GET_CYCLES(pkt_ctr), m_last_timestamp, + (unsigned int)TICKS_TO_CYCLES(m_last_timestamp) ); + packet->sid = m_local_node_id; + + packet->dbs = m_dimension; + packet->fn = 0; + packet->qpc = 0; + packet->sph = 0; + packet->reserved = 0; + packet->dbc = m_dbc; + packet->eoh1 = 2; + packet->fmt = IEC61883_FMT_AMDTP; + + *tag = IEC61883_TAG_WITH_CIP; + *sy = 0; + + m_dbc += fillNoDataPacketHeader(packet, length); + return eCRV_OK; +} + +enum StreamProcessor::eChildReturnValue +AmdtpTransmitStreamProcessor::generateEmptyPacketData ( + unsigned char *data, unsigned int *length ) +{ + return eCRV_OK; // no need to do anything +} + +unsigned int AmdtpTransmitStreamProcessor::fillDataPacketHeader ( + struct iec61883_packet *packet, unsigned int* length, + uint32_t ts ) +{ + + packet->fdf = m_fdf; + + // convert the timestamp to SYT format + uint16_t timestamp_SYT = TICKS_TO_SYT ( ts ); + packet->syt = CondSwapToBus16 ( timestamp_SYT ); + + // FIXME: use a precomputed value here + *length = m_syt_interval*sizeof ( quadlet_t ) *m_dimension + 8; + + return m_syt_interval; +} + +unsigned int AmdtpTransmitStreamProcessor::fillNoDataPacketHeader ( + struct iec61883_packet *packet, unsigned int* length ) +{ + // no-data packets have syt=0xFFFF + // and (can) have the usual amount of events as dummy data + // DBC is not increased + packet->fdf = IEC61883_FDF_NODATA; + packet->syt = 0xffff; + +#if AMDTP_ALLOW_PAYLOAD_IN_NODATA_XMIT + if ( m_send_nodata_payload ) + { // no-data packets with payload (NOTE: DICE-II doesn't like that) + *length = 2*sizeof ( quadlet_t ) + m_syt_interval * m_dimension * sizeof ( quadlet_t ); + return m_syt_interval; + } else { // no-data packets without payload + *length = 2*sizeof ( quadlet_t ); + return 0; + } +#else + // no-data packets without payload + *length = 2*sizeof ( quadlet_t ); + return 0; +#endif +} + +unsigned int +AmdtpTransmitStreamProcessor::getSytInterval() { + switch (m_StreamProcessorManager.getNominalRate()) { + case 32000: + case 44100: + case 48000: + return 8; + case 88200: + case 96000: + return 16; + case 176400: + case 192000: + return 32; + default: + debugError("Unsupported rate: %d\n", m_StreamProcessorManager.getNominalRate()); + return 0; + } +} + +unsigned int +AmdtpTransmitStreamProcessor::getFDF() { + switch (m_StreamProcessorManager.getNominalRate()) { + case 32000: return IEC61883_FDF_SFC_32KHZ; + case 44100: return IEC61883_FDF_SFC_44K1HZ; + case 48000: return IEC61883_FDF_SFC_48KHZ; + case 88200: return IEC61883_FDF_SFC_88K2HZ; + case 96000: return IEC61883_FDF_SFC_96KHZ; + case 176400: return IEC61883_FDF_SFC_176K4HZ; + case 192000: return IEC61883_FDF_SFC_192KHZ; + default: + debugError("Unsupported rate: %d\n", m_StreamProcessorManager.getNominalRate()); + return 0; + } +} + +bool AmdtpTransmitStreamProcessor::prepareChild() +{ + debugOutput ( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this ); + m_syt_interval = getSytInterval(); + m_fdf = getFDF(); + + debugOutput ( DEBUG_LEVEL_VERBOSE, " SYT interval / FDF : %d / %d\n", m_syt_interval, m_fdf ); +#if AMDTP_ALLOW_PAYLOAD_IN_NODATA_XMIT + debugOutput ( DEBUG_LEVEL_VERBOSE, " Send payload in No-Data packets: %s \n", m_send_nodata_payload?"Yes":"No" ); +#endif + debugOutput ( DEBUG_LEVEL_VERBOSE, " Max early transmit cycles : %d\n", m_max_cycles_to_transmit_early ); + debugOutput ( DEBUG_LEVEL_VERBOSE, " Transfer delay : %d\n", m_transmit_transfer_delay ); + debugOutput ( DEBUG_LEVEL_VERBOSE, " Min cycles before presentation : %d\n", m_min_cycles_before_presentation ); + + iec61883_cip_init ( + &m_cip_status, + IEC61883_FMT_AMDTP, + m_fdf, + m_StreamProcessorManager.getNominalRate(), + m_dimension, + m_syt_interval ); + + if (!initPortCache()) { + debugError("Could not init port cache\n"); + return false; + } + + return true; +} + +/* +* compose the event streams for the packets from the port buffers +*/ +bool AmdtpTransmitStreamProcessor::processWriteBlock ( char *data, + unsigned int nevents, unsigned int offset ) +{ + // update the variable parts of the cache + updatePortCache(); + + // encode audio data + switch(m_StreamProcessorManager.getAudioDataType()) { + case StreamProcessorManager::eADT_Int24: + encodeAudioPortsInt24((quadlet_t *)data, offset, nevents); + break; + case StreamProcessorManager::eADT_Float: + encodeAudioPortsFloat((quadlet_t *)data, offset, nevents); + break; + } + + // do midi ports + encodeMidiPorts((quadlet_t *)data, offset, nevents); + return true; +} + +bool +AmdtpTransmitStreamProcessor::transmitSilenceBlock( + char *data, unsigned int nevents, unsigned int offset) +{ + // no need to update the port cache when transmitting silence since + // no dynamic values are used to do so. + encodeAudioPortsSilence((quadlet_t *)data, offset, nevents); + encodeMidiPortsSilence((quadlet_t *)data, offset, nevents); + return true; +} + +/** + * @brief encodes all audio ports in the cache to events (silent data) + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsSilence(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + int i; + + for (i = 0; i < m_nb_audio_ports; i++) { + target_event = (quadlet_t *)(data + i); + + for (j = 0;j < nevents; j += 1) + { + *target_event = CONDSWAPTOBUS32_CONST(0x40000000); + target_event += m_dimension; + } + } +} + +#ifdef __SSE2__ +#include +#warning SSE2 build + +/** + * @brief mux all audio ports to events + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsFloat(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + int i; + + float * client_buffers[4]; + float tmp_values[4] __attribute__ ((aligned (16))); + uint32_t tmp_values_int[4] __attribute__ ((aligned (16))); + + // prepare the scratch buffer + assert(m_scratch_buffer_size_bytes > nevents * 4); + memset(m_scratch_buffer, 0, nevents * 4); + + const __m128i label = _mm_set_epi32 (0x40000000, 0x40000000, 0x40000000, 0x40000000); + const __m128i mask = _mm_set_epi32 (0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF); + const __m128 mult = _mm_set_ps(AMDTP_FLOAT_MULTIPLIER, AMDTP_FLOAT_MULTIPLIER, AMDTP_FLOAT_MULTIPLIER, AMDTP_FLOAT_MULTIPLIER); + +#if AMDTP_CLIP_FLOATS + const __m128 v_max = _mm_set_ps(1.0, 1.0, 1.0, 1.0); + const __m128 v_min = _mm_set_ps(-1.0, -1.0, -1.0, -1.0); +#endif + + // this assumes that audio ports are sorted by position, + // and that there are no gaps + for (i = 0; i < ((int)m_nb_audio_ports)-4; i += 4) { + struct _MBLA_port_cache *p; + + // get the port buffers + for (j=0; j<4; j++) { + p = &(m_audio_ports.at(i+j)); + if(likely(p->buffer && p->enabled)) { + client_buffers[j] = (float *) p->buffer; + client_buffers[j] += offset; + } else { + // if a port is disabled or has no valid + // buffer, use the scratch buffer (all zero's) + client_buffers[j] = (float *) m_scratch_buffer; + } + } + + // the base event for this position + target_event = (quadlet_t *)(data + i); + // process the events + for (j=0;j < nevents; j += 1) + { + // read the values + tmp_values[0] = *(client_buffers[0]); + tmp_values[1] = *(client_buffers[1]); + tmp_values[2] = *(client_buffers[2]); + tmp_values[3] = *(client_buffers[3]); + + // now do the SSE based conversion/labeling + __m128 v_float = *((__m128*)tmp_values); + __m128i *target = (__m128i*)target_event; + __m128i v_int; + + // clip +#if AMDTP_CLIP_FLOATS + // do SSE clipping + v_float = _mm_max_ps(v_float, v_min); + v_float = _mm_min_ps(v_float, v_max); +#endif + + // multiply + v_float = _mm_mul_ps(v_float, mult); + // convert to signed integer + v_int = _mm_cvttps_epi32( v_float ); + // mask + v_int = _mm_and_si128( v_int, mask ); + // label it + v_int = _mm_or_si128( v_int, label ); + + // do endian conversion (SSE is always little endian) + // do first swap + v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); + // do second swap + v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); + // store the packed int + // (target misalignment is assumed since we don't know the m_dimension) + _mm_storeu_si128 (target, v_int); + + // increment the buffer pointers + client_buffers[0]++; + client_buffers[1]++; + client_buffers[2]++; + client_buffers[3]++; + + // go to next target event position + target_event += m_dimension; + } + } + + // do remaining ports + // NOTE: these can be time-SSE'd + for (; i < (int)m_nb_audio_ports; i++) { + struct _MBLA_port_cache &p = m_audio_ports.at(i); + target_event = (quadlet_t *)(data + i); + assert(nevents + offset <= p.buffer_size ); + + if(likely(p.buffer && p.enabled)) { + float *buffer = (float *)(p.buffer); + buffer += offset; + + for (j = 0;j < nevents; j += 4) + { + // read the values + tmp_values[0] = *buffer; + buffer++; + tmp_values[1] = *buffer; + buffer++; + tmp_values[2] = *buffer; + buffer++; + tmp_values[3] = *buffer; + buffer++; + + // now do the SSE based conversion/labeling + __m128 v_float = *((__m128*)tmp_values); + __m128i v_int; + +#if AMDTP_CLIP_FLOATS + // do SSE clipping + v_float = _mm_max_ps(v_float, v_min); + v_float = _mm_min_ps(v_float, v_max); +#endif + // multiply + v_float = _mm_mul_ps(v_float, mult); + // convert to signed integer + v_int = _mm_cvttps_epi32( v_float ); + // mask + v_int = _mm_and_si128( v_int, mask ); + // label it + v_int = _mm_or_si128( v_int, label ); + + // do endian conversion (SSE is always little endian) + // do first swap + v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); + // do second swap + v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); + + // store the packed int + _mm_store_si128 ((__m128i *)(&tmp_values_int), v_int); + + // increment the buffer pointers + *target_event = tmp_values_int[0]; + target_event += m_dimension; + *target_event = tmp_values_int[1]; + target_event += m_dimension; + *target_event = tmp_values_int[2]; + target_event += m_dimension; + *target_event = tmp_values_int[3]; + target_event += m_dimension; + } + + // do the remainder of the events + for(;j < nevents; j += 1) { + float *in = (float *)buffer; +#if AMDTP_CLIP_FLOATS + // clip directly to the value of a maxed event + if(unlikely(*in > 1.0)) { + *target_event = CONDSWAPTOBUS32_CONST(0x407FFFFF); + } else if(unlikely(*in < -1.0)) { + *target_event = CONDSWAPTOBUS32_CONST(0x40800001); + } else { + float v = (*in) * AMDTP_FLOAT_MULTIPLIER; + unsigned int tmp = ((int) v); + tmp = ( tmp & 0x00FFFFFF ) | 0x40000000; + *target_event = CondSwapToBus32((quadlet_t)tmp); + } +#else + float v = (*in) * AMDTP_FLOAT_MULTIPLIER; + unsigned int tmp = ((int) v); + tmp = ( tmp & 0x00FFFFFF ) | 0x40000000; + *target_event = CondSwapToBus32((quadlet_t)tmp); +#endif + buffer++; + target_event += m_dimension; + } + + } else { + for (j = 0;j < nevents; j += 1) + { + // hardcoded byte swapped + *target_event = 0x00000040; + target_event += m_dimension; + } + } + } +} + + +/** + * @brief mux all audio ports to events + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsInt24(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + int i; + + uint32_t *client_buffers[4]; + uint32_t tmp_values[4] __attribute__ ((aligned (16))); + + // prepare the scratch buffer + assert(m_scratch_buffer_size_bytes > nevents * 4); + memset(m_scratch_buffer, 0, nevents * 4); + + const __m128i label = _mm_set_epi32 (0x40000000, 0x40000000, 0x40000000, 0x40000000); + const __m128i mask = _mm_set_epi32 (0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF); + + // this assumes that audio ports are sorted by position, + // and that there are no gaps + for (i = 0; i < ((int)m_nb_audio_ports)-4; i += 4) { + struct _MBLA_port_cache *p; + + // get the port buffers + for (j=0; j<4; j++) { + p = &(m_audio_ports.at(i+j)); + if(likely(p->buffer && p->enabled)) { + client_buffers[j] = (uint32_t *) p->buffer; + client_buffers[j] += offset; + } else { + // if a port is disabled or has no valid + // buffer, use the scratch buffer (all zero's) + client_buffers[j] = (uint32_t *) m_scratch_buffer; + } + } + + // the base event for this position + target_event = (quadlet_t *)(data + i); + + // process the events + for (j=0;j < nevents; j += 1) + { + // read the values + tmp_values[0] = *(client_buffers[0]); + tmp_values[1] = *(client_buffers[1]); + tmp_values[2] = *(client_buffers[2]); + tmp_values[3] = *(client_buffers[3]); + + // now do the SSE based conversion/labeling + __m128i *target = (__m128i*)target_event; + __m128i v_int = *((__m128i*)tmp_values);; + + // mask + v_int = _mm_and_si128( v_int, mask ); + // label it + v_int = _mm_or_si128( v_int, label ); + + // do endian conversion (SSE is always little endian) + // do first swap + v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); + // do second swap + v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); + + // store the packed int + // (target misalignment is assumed since we don't know the m_dimension) + _mm_storeu_si128 (target, v_int); + + // increment the buffer pointers + client_buffers[0]++; + client_buffers[1]++; + client_buffers[2]++; + client_buffers[3]++; + + // go to next target event position + target_event += m_dimension; + } + } + + // do remaining ports + // NOTE: these can be time-SSE'd + for (; i < ((int)m_nb_audio_ports); i++) { + struct _MBLA_port_cache &p = m_audio_ports.at(i); + target_event = (quadlet_t *)(data + i); + assert(nevents + offset <= p.buffer_size ); + + if(likely(p.buffer && p.enabled)) { + uint32_t *buffer = (uint32_t *)(p.buffer); + buffer += offset; + + for (j = 0;j < nevents; j += 4) + { + // read the values + tmp_values[0] = *buffer; + buffer++; + tmp_values[1] = *buffer; + buffer++; + tmp_values[2] = *buffer; + buffer++; + tmp_values[3] = *buffer; + buffer++; + + // now do the SSE based conversion/labeling + __m128i v_int = *((__m128i*)tmp_values);; + + // mask + v_int = _mm_and_si128( v_int, mask ); + // label it + v_int = _mm_or_si128( v_int, label ); + + // do endian conversion (SSE is always little endian) + // do first swap + v_int = _mm_or_si128( _mm_slli_epi16( v_int, 8 ), _mm_srli_epi16( v_int, 8 ) ); + // do second swap + v_int = _mm_or_si128( _mm_slli_epi32( v_int, 16 ), _mm_srli_epi32( v_int, 16 ) ); + + // store the packed int + _mm_store_si128 ((__m128i *)(&tmp_values), v_int); + + // increment the buffer pointers + *target_event = tmp_values[0]; + target_event += m_dimension; + *target_event = tmp_values[1]; + target_event += m_dimension; + *target_event = tmp_values[2]; + target_event += m_dimension; + *target_event = tmp_values[3]; + target_event += m_dimension; + } + + // do the remainder of the events + for(;j < nevents; j += 1) { + uint32_t in = (uint32_t)(*buffer); + *target_event = CondSwapToBus32((quadlet_t)((in & 0x00FFFFFF) | 0x40000000)); + buffer++; + target_event += m_dimension; + } + + } else { + for (j = 0;j < nevents; j += 1) + { + // hardcoded byte swapped + *target_event = 0x00000040; + target_event += m_dimension; + } + } + } +} + +#else + +/** + * @brief mux all audio ports to events + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsInt24(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + int i; + + for (i = 0; i < m_nb_audio_ports; i++) { + struct _MBLA_port_cache &p = m_audio_ports.at(i); + target_event = (quadlet_t *)(data + i); + assert(nevents + offset <= p.buffer_size ); + + if(likely(p.buffer && p.enabled)) { + quadlet_t *buffer = (quadlet_t *)(p.buffer); + buffer += offset; + + for (j = 0;j < nevents; j += 1) + { + uint32_t in = (uint32_t)(*buffer); + *target_event = CondSwapToBus32((quadlet_t)((in & 0x00FFFFFF) | 0x40000000)); + buffer++; + target_event += m_dimension; + } + } else { + for (j = 0;j < nevents; j += 1) + { + *target_event = CONDSWAPTOBUS32_CONST(0x40000000); + target_event += m_dimension; + } + } + } +} + +/** + * @brief mux all audio ports to events + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeAudioPortsFloat(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + unsigned int j; + quadlet_t *target_event; + int i; + + for (i = 0; i < m_nb_audio_ports; i++) { + struct _MBLA_port_cache &p = m_audio_ports.at(i); + target_event = (quadlet_t *)(data + i); + assert(nevents + offset <= p.buffer_size ); + + if(likely(p.buffer && p.enabled)) { + quadlet_t *buffer = (quadlet_t *)(p.buffer); + buffer += offset; + + for (j = 0;j < nevents; j += 1) + { + float *in = (float *)buffer; +#if AMDTP_CLIP_FLOATS + // clip directly to the value of a maxed event + if(unlikely(*in > 1.0)) { + *target_event = CONDSWAPTOBUS32_CONST(0x407FFFFF); + } else if(unlikely(*in < -1.0)) { + *target_event = CONDSWAPTOBUS32_CONST(0x40800001); + } else { + float v = (*in) * AMDTP_FLOAT_MULTIPLIER; + unsigned int tmp = ((int) v); + tmp = ( tmp & 0x00FFFFFF ) | 0x40000000; + *target_event = CondSwapToBus32((quadlet_t)tmp); + } +#else + float v = (*in) * AMDTP_FLOAT_MULTIPLIER; + unsigned int tmp = ((int) v); + tmp = ( tmp & 0x00FFFFFF ) | 0x40000000; + *target_event = CondSwapToBus32((quadlet_t)tmp); +#endif + buffer++; + target_event += m_dimension; + } + } else { + for (j = 0;j < nevents; j += 1) + { + *target_event = CONDSWAPTOBUS32_CONST(0x40000000); + target_event += m_dimension; + } + } + } +} +#endif + +/** + * @brief encodes all midi ports in the cache to events (silence) + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeMidiPortsSilence(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + quadlet_t *target_event; + int i; + unsigned int j; + + for (i = 0; i < m_nb_midi_ports; i++) { + struct _MIDI_port_cache &p = m_midi_ports.at(i); + + for (j = p.location;j < nevents; j += 8) { + target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); + *target_event = CondSwapToBus32(IEC61883_AM824_SET_LABEL(0, IEC61883_AM824_LABEL_MIDI_NO_DATA)); + } + } +} + +/** + * @brief encodes all midi ports in the cache to events + * @param data + * @param offset + * @param nevents + */ +void +AmdtpTransmitStreamProcessor::encodeMidiPorts(quadlet_t *data, + unsigned int offset, + unsigned int nevents) +{ + quadlet_t *target_event; + int i; + unsigned int j; + + for (i = 0; i < m_nb_midi_ports; i++) { + struct _MIDI_port_cache &p = m_midi_ports.at(i); + if (p.buffer && p.enabled) { + uint32_t *buffer = (quadlet_t *)(p.buffer); + buffer += offset; + + for (j = p.location;j < nevents; j += 8) { + target_event = (quadlet_t *) (data + ((j * m_dimension) + p.position)); + + if ( *buffer & 0xFF000000 ) // we can send a byte + { + quadlet_t tmpval; + tmpval = ((*buffer)<<16) &