X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmiracle%2Fmiracle_commands.c;fp=src%2Fmiracle%2Fmiracle_commands.c;h=8a492d1ae9e20b1845ed1c391a9abffeadde1970;hb=661165812e3410fe2f6f49d7af882b36a0efcf82;hp=0000000000000000000000000000000000000000;hpb=2083c672e1df59eafdad871b66f1bb2eaedfcc04;p=melted diff --git a/src/miracle/miracle_commands.c b/src/miracle/miracle_commands.c new file mode 100644 index 0000000..8a492d1 --- /dev/null +++ b/src/miracle/miracle_commands.c @@ -0,0 +1,453 @@ +/* + * global_commands.c + * Copyright (C) 2002-2003 Ushodaya Enterprises Limited + * Author: Dan Dennedy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvunit.h" +#include "global_commands.h" +#include "raw1394util.h" +#include +#include "log.h" + +static dv_unit g_units[MAX_UNITS]; + + +/** Return the dv_unit given a numeric index. +*/ + +dv_unit dv1394d_get_unit( int n ) +{ + if (n < MAX_UNITS) + return g_units[n]; + else + return NULL; +} + +/** Destroy the dv_unit given its numeric index. +*/ + +void dv1394d_delete_unit( int n ) +{ + if (n < MAX_UNITS) + { + dv_unit unit = dv1394d_get_unit(n); + if (unit != NULL) + { + dv_unit_close( unit ); + g_units[ n ] = NULL; + dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", n ); + } + } +} + +/** Destroy all allocated units on the server. +*/ + +void dv1394d_delete_all_units( void ) +{ + int i; + for (i = 0; i < MAX_UNITS; i++) + if ( dv1394d_get_unit(i) != NULL ) + { + dv_unit_close( dv1394d_get_unit(i) ); + dv1394d_log( LOG_NOTICE, "Deleted unit U%d.", i ); + } +} + +/** Add a DV virtual vtr to the server. +*/ +response_codes dv1394d_add_unit( command_argument cmd_arg ) +{ + int i; + int channel = -1; + char *guid_str = (char*) cmd_arg->argument; + octlet_t guid; + uint32_t guid_hi; + uint32_t guid_lo; + + sscanf( guid_str, "%08x%08x", &guid_hi, &guid_lo ); + guid = (octlet_t)guid_hi << 32 | (octlet_t) guid_lo; + + if ( dv_tokeniser_count( cmd_arg->tokeniser ) == 3 ) + channel = atoi( dv_tokeniser_get_string( cmd_arg->tokeniser, 2 ) ); + + /* make sure unit does not already exit */ + for (i = 0; i < MAX_UNITS; i++) + { + if (g_units[i] != NULL) + if ( dv_unit_get_guid( g_units[i] ) == guid ) + { + dv_response_printf( cmd_arg->response, 1024, "a unit already exists for that node\n\n" ); + return RESPONSE_ERROR; + } + } + + for (i = 0; i < MAX_UNITS; i++) + { + if (g_units[i] == NULL) + { + + g_units[ i ] = dv_unit_init( guid, channel ); + if ( g_units[ i ] == NULL ) + { + dv_response_printf( cmd_arg->response, 1024, "failed to allocate unit\n" ); + return RESPONSE_ERROR; + } + g_units[ i ]->unit = i; + dv_unit_set_notifier( g_units[ i ], dv_parser_get_notifier( cmd_arg->parser ), cmd_arg->root_dir ); + + dv1394d_log( LOG_NOTICE, "added unit %d to send to node %d over channel %d", + i, dv_unit_get_nodeid( g_units[i] ), dv_unit_get_channel( g_units[i] ) ); + dv_response_printf( cmd_arg->response, 10, "U%1d\n\n", i ); + return RESPONSE_SUCCESS_N; + } + } + + dv_response_printf( cmd_arg->response, 1024, "no more units can be created\n\n" ); + + return RESPONSE_ERROR; +} + + +/** List all AV/C nodes on the bus. +*/ +response_codes dv1394d_list_nodes( command_argument cmd_arg ) +{ + response_codes error = RESPONSE_SUCCESS_N; + raw1394handle_t handle; + int i, j; + char line[1024]; + octlet_t guid; + rom1394_directory dir; + + for ( j = 0; j < raw1394_get_num_ports(); j++ ) + { + handle = raw1394_open(j); + for ( i = 0; i < raw1394_get_nodecount(handle); ++i ) + { + rom1394_get_directory( handle, i, &dir); + if ( (rom1394_get_node_type(&dir) == ROM1394_NODE_TYPE_AVC) ) + { + guid = rom1394_get_guid(handle, i); + if (dir.label != NULL) + { + snprintf( line, 1023, "%02d %08x%08x \"%s\"\n", i, + (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), dir.label ); + } else { + snprintf( line, 1023, "%02d %08x%08x \"Unlabeled Node %d\"\n", i, + (quadlet_t) (guid>>32), (quadlet_t) (guid & 0xffffffff), i ); + } + dv_response_write( cmd_arg->response, line, strlen(line) ); + rom1394_free_directory( &dir); + } + } + raw1394_close( handle ); + } + dv_response_write( cmd_arg->response, "\n", 1 ); + return error; +} + + +/** List units already added to server. +*/ +response_codes dv1394d_list_units( command_argument cmd_arg ) +{ + response_codes error = RESPONSE_SUCCESS_N; + char line[1024]; + int i; + + for (i = 0; i < MAX_UNITS; i++) + { + if (dv1394d_get_unit(i) != NULL) + { + snprintf( line, 1023, "U%d %02d %08x%08x %d\n", i, dv_unit_get_nodeid(g_units[i]), + (quadlet_t) (dv_unit_get_guid(g_units[i]) >> 32), + (quadlet_t) (dv_unit_get_guid(g_units[i]) & 0xffffffff), + !dv_unit_is_offline( g_units[i] ) ); + dv_response_write( cmd_arg->response, line, strlen(line) ); + } + } + dv_response_write( cmd_arg->response, "\n", 1 ); + + return error; +} + +static int +filter_files( const struct dirent *de ) +{ + if ( de->d_name[ 0 ] != '.' ) + return 1; + else + return 0; +} + +/** List clips in a directory. +*/ +response_codes dv1394d_list_clips( command_argument cmd_arg ) +{ + response_codes error = RESPONSE_BAD_FILE; + const char *dir_name = (const char*) cmd_arg->argument; + DIR *dir; + char fullname[1024]; + struct dirent **de = NULL; + int i, n; + + snprintf( fullname, 1023, "%s%s", cmd_arg->root_dir, dir_name ); + dir = opendir( fullname ); + if (dir != NULL) + { + struct stat info; + error = RESPONSE_SUCCESS_N; + n = scandir( fullname, &de, filter_files, alphasort ); + for (i = 0; i < n; i++ ) + { + snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name ); + if ( stat( fullname, &info ) == 0 && S_ISDIR( info.st_mode ) ) + dv_response_printf( cmd_arg->response, 1024, "\"%s/\"\n", de[i]->d_name ); + } + for (i = 0; i < n; i++ ) + { + snprintf( fullname, 1023, "%s%s/%s", cmd_arg->root_dir, dir_name, de[i]->d_name ); + if ( lstat( fullname, &info ) == 0 && + ( S_ISREG( info.st_mode ) || ( strstr( fullname, ".clip" ) && info.st_mode | S_IXUSR ) ) ) + dv_response_printf( cmd_arg->response, 1024, "\"%s\" %llu\n", de[i]->d_name, (unsigned long long) info.st_size ); + free( de[ i ] ); + } + free( de ); + closedir( dir ); + dv_response_write( cmd_arg->response, "\n", 1 ); + } + + return error; +} + +/** Set a server configuration property. +*/ + +response_codes dv1394d_set_global_property( command_argument cmd_arg ) +{ + char *key = (char*) cmd_arg->argument; + char *value = NULL; + + value = strchr( key, '=' ); + if (value == NULL) + return RESPONSE_OUT_OF_RANGE; + *value = 0; + value++; + dv1394d_log( LOG_DEBUG, "SET %s = %s", key, value ); + + if ( strncasecmp( key, "root", 1024) == 0 ) + { + int len = strlen(value); + int i; + + /* stop all units and unload clips */ + for (i = 0; i < MAX_UNITS; i++) + { + if (g_units[i] != NULL) + dv_unit_terminate( g_units[i] ); + } + + /* set the property */ + strncpy( cmd_arg->root_dir, value, 1023 ); + + /* add a trailing slash if needed */ + if ( cmd_arg->root_dir[ len - 1 ] != '/') + { + cmd_arg->root_dir[ len ] = '/'; + cmd_arg->root_dir[ len + 1 ] = '\0'; + } + } + else + return RESPONSE_OUT_OF_RANGE; + + return RESPONSE_SUCCESS; +} + +/** Get a server configuration property. +*/ + +response_codes dv1394d_get_global_property( command_argument cmd_arg ) +{ + char *key = (char*) cmd_arg->argument; + + if ( strncasecmp( key, "root", 1024) == 0 ) + { + dv_response_write( cmd_arg->response, cmd_arg->root_dir, strlen(cmd_arg->root_dir) ); + return RESPONSE_SUCCESS_1; + } + else + return RESPONSE_OUT_OF_RANGE; + + return RESPONSE_SUCCESS; +} + +/** IEEE 1394 Bus Reset handler + + This is included here for now due to all the unit management involved. +*/ + +static int reset_handler( raw1394handle_t h, unsigned int generation ) +{ + int i, j, count, retry = 3; + int port = (int) raw1394_get_userdata( h ); + + raw1394_update_generation( h, generation ); + dv1394d_log( LOG_NOTICE, "bus reset on port %d", port ); + + while ( retry-- > 0 ) + { + raw1394handle_t handle = raw1394_open( port ); + count = raw1394_get_nodecount( handle ); + + if ( count > 0 ) + { + dv1394d_log( LOG_DEBUG, "bus reset, checking units" ); + + /* suspend all units on this port */ + for ( j = MAX_UNITS; j > 0; j-- ) + { + if ( g_units[ j-1 ] != NULL && dv_unit_get_port( g_units[ j-1 ] ) == port ) + dv_unit_suspend( g_units[ j-1 ] ); + } + dv1394d_log( LOG_DEBUG, "All units are now stopped" ); + + /* restore units with known guid, take others offline */ + for ( j = 0; j < MAX_UNITS; j++ ) + { + if ( g_units[j] != NULL && + ( dv_unit_get_port( g_units[ j ] ) == port || dv_unit_get_port( g_units[ j ] ) == -1 ) ) + { + int found = 0; + for ( i = 0; i < count; i++ ) + { + octlet_t guid; + dv1394d_log( LOG_DEBUG, "attempting to get guid for node %d", i ); + guid = rom1394_get_guid( handle, i ); + if ( guid == g_units[ j ]->guid ) + { + dv1394d_log( LOG_NOTICE, "unit with GUID %08x%08x found", + (quadlet_t) (g_units[j]->guid>>32), (quadlet_t) (g_units[j]->guid & 0xffffffff)); + if ( dv_unit_is_offline( g_units[ j ] ) ) + dv_unit_online( g_units[ j ] ); + else + dv_unit_restore( g_units[ j ] ); + found = 1; + break; + } + } + if ( found == 0 ) + dv_unit_offline( g_units[ j ] ); + } + } + dv1394d_log( LOG_DEBUG, "completed bus reset handler"); + raw1394_close( handle ); + return 0; + } + raw1394_close( handle ); + } + dv1394d_log( LOG_CRIT, "raw1394 reported zero nodes on the bus!" ); + return 0; +} + + +/** One pthread per IEEE 1394 port +*/ + +static pthread_t raw1394service_thread[4]; + +/** One raw1394 handle for each pthread/port +*/ + +static raw1394handle_t raw1394service_handle[4]; + +/** The service thread that polls raw1394 for new events. +*/ + +static void* raw1394_service( void *arg ) +{ + raw1394handle_t handle = (raw1394handle_t) arg; + struct pollfd raw1394_poll; + raw1394_poll.fd = raw1394_get_fd( handle ); + raw1394_poll.events = POLLIN; + raw1394_poll.revents = 0; + while ( 1 ) + { + if ( poll( &raw1394_poll, 1, 200) > 0 ) + { + if ( (raw1394_poll.revents & POLLIN) + || (raw1394_poll.revents & POLLPRI) ) + raw1394_loop_iterate( handle ); + } + pthread_testcancel(); + } + +} + + +/** Start the raw1394 service threads for handling bus reset. + + One thread is launched per port on the system. +*/ + +void raw1394_start_service_threads( void ) +{ + int port; + for ( port = 0; port < raw1394_get_num_ports(); port++ ) + { + raw1394service_handle[port] = raw1394_open( port ); + raw1394_set_bus_reset_handler( raw1394service_handle[port], reset_handler ); + pthread_create( &(raw1394service_thread[port]), NULL, raw1394_service, raw1394service_handle[port] ); + } + for ( ; port < 4; port++ ) + raw1394service_handle[port] = NULL; +} + +/** Shutdown all the raw1394 service threads. +*/ + +void raw1394_stop_service_threads( void ) +{ + int i; + for ( i = 0; i < 4; i++ ) + { + if ( raw1394service_handle[i] != NULL ) + { + pthread_cancel( raw1394service_thread[i] ); + pthread_join( raw1394service_thread[i], NULL ); + raw1394_close( raw1394service_handle[i] ); + } + } +} + +