3 * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4 * Author: Dan Dennedy <dan@dennedy.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <sys/types.h>
37 #include "global_commands.h"
38 #include "raw1394util.h"
39 #include <libavc1394/rom1394.h>
42 static dv_unit g_units
[MAX_UNITS
];
45 /** Return the dv_unit given a numeric index.
48 dv_unit
dv1394d_get_unit( int n
)
56 /** Destroy the dv_unit given its numeric index.
59 void dv1394d_delete_unit( int n
)
63 dv_unit unit
= dv1394d_get_unit(n
);
66 dv_unit_close( unit
);
68 dv1394d_log( LOG_NOTICE
, "Deleted unit U%d.", n
);
73 /** Destroy all allocated units on the server.
76 void dv1394d_delete_all_units( void )
79 for (i
= 0; i
< MAX_UNITS
; i
++)
80 if ( dv1394d_get_unit(i
) != NULL
)
82 dv_unit_close( dv1394d_get_unit(i
) );
83 dv1394d_log( LOG_NOTICE
, "Deleted unit U%d.", i
);
87 /** Add a DV virtual vtr to the server.
89 response_codes
dv1394d_add_unit( command_argument cmd_arg
)
93 char *guid_str
= (char*) cmd_arg
->argument
;
98 sscanf( guid_str
, "%08x%08x", &guid_hi
, &guid_lo
);
99 guid
= (octlet_t
)guid_hi
<< 32 | (octlet_t
) guid_lo
;
101 if ( dv_tokeniser_count( cmd_arg
->tokeniser
) == 3 )
102 channel
= atoi( dv_tokeniser_get_string( cmd_arg
->tokeniser
, 2 ) );
104 /* make sure unit does not already exit */
105 for (i
= 0; i
< MAX_UNITS
; i
++)
107 if (g_units
[i
] != NULL
)
108 if ( dv_unit_get_guid( g_units
[i
] ) == guid
)
110 dv_response_printf( cmd_arg
->response
, 1024, "a unit already exists for that node\n\n" );
111 return RESPONSE_ERROR
;
115 for (i
= 0; i
< MAX_UNITS
; i
++)
117 if (g_units
[i
] == NULL
)
120 g_units
[ i
] = dv_unit_init( guid
, channel
);
121 if ( g_units
[ i
] == NULL
)
123 dv_response_printf( cmd_arg
->response
, 1024, "failed to allocate unit\n" );
124 return RESPONSE_ERROR
;
126 g_units
[ i
]->unit
= i
;
127 dv_unit_set_notifier( g_units
[ i
], dv_parser_get_notifier( cmd_arg
->parser
), cmd_arg
->root_dir
);
129 dv1394d_log( LOG_NOTICE
, "added unit %d to send to node %d over channel %d",
130 i
, dv_unit_get_nodeid( g_units
[i
] ), dv_unit_get_channel( g_units
[i
] ) );
131 dv_response_printf( cmd_arg
->response
, 10, "U%1d\n\n", i
);
132 return RESPONSE_SUCCESS_N
;
136 dv_response_printf( cmd_arg
->response
, 1024, "no more units can be created\n\n" );
138 return RESPONSE_ERROR
;
142 /** List all AV/C nodes on the bus.
144 response_codes
dv1394d_list_nodes( command_argument cmd_arg
)
146 response_codes error
= RESPONSE_SUCCESS_N
;
147 raw1394handle_t handle
;
151 rom1394_directory dir
;
153 for ( j
= 0; j
< raw1394_get_num_ports(); j
++ )
155 handle
= raw1394_open(j
);
156 for ( i
= 0; i
< raw1394_get_nodecount(handle
); ++i
)
158 rom1394_get_directory( handle
, i
, &dir
);
159 if ( (rom1394_get_node_type(&dir
) == ROM1394_NODE_TYPE_AVC
) )
161 guid
= rom1394_get_guid(handle
, i
);
162 if (dir
.label
!= NULL
)
164 snprintf( line
, 1023, "%02d %08x%08x \"%s\"\n", i
,
165 (quadlet_t
) (guid
>>32), (quadlet_t
) (guid
& 0xffffffff), dir
.label
);
167 snprintf( line
, 1023, "%02d %08x%08x \"Unlabeled Node %d\"\n", i
,
168 (quadlet_t
) (guid
>>32), (quadlet_t
) (guid
& 0xffffffff), i
);
170 dv_response_write( cmd_arg
->response
, line
, strlen(line
) );
171 rom1394_free_directory( &dir
);
174 raw1394_close( handle
);
176 dv_response_write( cmd_arg
->response
, "\n", 1 );
181 /** List units already added to server.
183 response_codes
dv1394d_list_units( command_argument cmd_arg
)
185 response_codes error
= RESPONSE_SUCCESS_N
;
189 for (i
= 0; i
< MAX_UNITS
; i
++)
191 if (dv1394d_get_unit(i
) != NULL
)
193 snprintf( line
, 1023, "U%d %02d %08x%08x %d\n", i
, dv_unit_get_nodeid(g_units
[i
]),
194 (quadlet_t
) (dv_unit_get_guid(g_units
[i
]) >> 32),
195 (quadlet_t
) (dv_unit_get_guid(g_units
[i
]) & 0xffffffff),
196 !dv_unit_is_offline( g_units
[i
] ) );
197 dv_response_write( cmd_arg
->response
, line
, strlen(line
) );
200 dv_response_write( cmd_arg
->response
, "\n", 1 );
206 filter_files( const struct dirent
*de
)
208 if ( de
->d_name
[ 0 ] != '.' )
214 /** List clips in a directory.
216 response_codes
dv1394d_list_clips( command_argument cmd_arg
)
218 response_codes error
= RESPONSE_BAD_FILE
;
219 const char *dir_name
= (const char*) cmd_arg
->argument
;
222 struct dirent
**de
= NULL
;
225 snprintf( fullname
, 1023, "%s%s", cmd_arg
->root_dir
, dir_name
);
226 dir
= opendir( fullname
);
230 error
= RESPONSE_SUCCESS_N
;
231 n
= scandir( fullname
, &de
, filter_files
, alphasort
);
232 for (i
= 0; i
< n
; i
++ )
234 snprintf( fullname
, 1023, "%s%s/%s", cmd_arg
->root_dir
, dir_name
, de
[i
]->d_name
);
235 if ( stat( fullname
, &info
) == 0 && S_ISDIR( info
.st_mode
) )
236 dv_response_printf( cmd_arg
->response
, 1024, "\"%s/\"\n", de
[i
]->d_name
);
238 for (i
= 0; i
< n
; i
++ )
240 snprintf( fullname
, 1023, "%s%s/%s", cmd_arg
->root_dir
, dir_name
, de
[i
]->d_name
);
241 if ( lstat( fullname
, &info
) == 0 &&
242 ( S_ISREG( info
.st_mode
) || ( strstr( fullname
, ".clip" ) && info
.st_mode
| S_IXUSR
) ) )
243 dv_response_printf( cmd_arg
->response
, 1024, "\"%s\" %llu\n", de
[i
]->d_name
, (unsigned long long) info
.st_size
);
248 dv_response_write( cmd_arg
->response
, "\n", 1 );
254 /** Set a server configuration property.
257 response_codes
dv1394d_set_global_property( command_argument cmd_arg
)
259 char *key
= (char*) cmd_arg
->argument
;
262 value
= strchr( key
, '=' );
264 return RESPONSE_OUT_OF_RANGE
;
267 dv1394d_log( LOG_DEBUG
, "SET %s = %s", key
, value
);
269 if ( strncasecmp( key
, "root", 1024) == 0 )
271 int len
= strlen(value
);
274 /* stop all units and unload clips */
275 for (i
= 0; i
< MAX_UNITS
; i
++)
277 if (g_units
[i
] != NULL
)
278 dv_unit_terminate( g_units
[i
] );
281 /* set the property */
282 strncpy( cmd_arg
->root_dir
, value
, 1023 );
284 /* add a trailing slash if needed */
285 if ( cmd_arg
->root_dir
[ len
- 1 ] != '/')
287 cmd_arg
->root_dir
[ len
] = '/';
288 cmd_arg
->root_dir
[ len
+ 1 ] = '\0';
292 return RESPONSE_OUT_OF_RANGE
;
294 return RESPONSE_SUCCESS
;
297 /** Get a server configuration property.
300 response_codes
dv1394d_get_global_property( command_argument cmd_arg
)
302 char *key
= (char*) cmd_arg
->argument
;
304 if ( strncasecmp( key
, "root", 1024) == 0 )
306 dv_response_write( cmd_arg
->response
, cmd_arg
->root_dir
, strlen(cmd_arg
->root_dir
) );
307 return RESPONSE_SUCCESS_1
;
310 return RESPONSE_OUT_OF_RANGE
;
312 return RESPONSE_SUCCESS
;
315 /** IEEE 1394 Bus Reset handler
317 This is included here for now due to all the unit management involved.
320 static int reset_handler( raw1394handle_t h
, unsigned int generation
)
322 int i
, j
, count
, retry
= 3;
323 int port
= (int) raw1394_get_userdata( h
);
325 raw1394_update_generation( h
, generation
);
326 dv1394d_log( LOG_NOTICE
, "bus reset on port %d", port
);
328 while ( retry
-- > 0 )
330 raw1394handle_t handle
= raw1394_open( port
);
331 count
= raw1394_get_nodecount( handle
);
335 dv1394d_log( LOG_DEBUG
, "bus reset, checking units" );
337 /* suspend all units on this port */
338 for ( j
= MAX_UNITS
; j
> 0; j
-- )
340 if ( g_units
[ j
-1 ] != NULL
&& dv_unit_get_port( g_units
[ j
-1 ] ) == port
)
341 dv_unit_suspend( g_units
[ j
-1 ] );
343 dv1394d_log( LOG_DEBUG
, "All units are now stopped" );
345 /* restore units with known guid, take others offline */
346 for ( j
= 0; j
< MAX_UNITS
; j
++ )
348 if ( g_units
[j
] != NULL
&&
349 ( dv_unit_get_port( g_units
[ j
] ) == port
|| dv_unit_get_port( g_units
[ j
] ) == -1 ) )
352 for ( i
= 0; i
< count
; i
++ )
355 dv1394d_log( LOG_DEBUG
, "attempting to get guid for node %d", i
);
356 guid
= rom1394_get_guid( handle
, i
);
357 if ( guid
== g_units
[ j
]->guid
)
359 dv1394d_log( LOG_NOTICE
, "unit with GUID %08x%08x found",
360 (quadlet_t
) (g_units
[j
]->guid
>>32), (quadlet_t
) (g_units
[j
]->guid
& 0xffffffff));
361 if ( dv_unit_is_offline( g_units
[ j
] ) )
362 dv_unit_online( g_units
[ j
] );
364 dv_unit_restore( g_units
[ j
] );
370 dv_unit_offline( g_units
[ j
] );
373 dv1394d_log( LOG_DEBUG
, "completed bus reset handler");
374 raw1394_close( handle
);
377 raw1394_close( handle
);
379 dv1394d_log( LOG_CRIT
, "raw1394 reported zero nodes on the bus!" );
384 /** One pthread per IEEE 1394 port
387 static pthread_t raw1394service_thread
[4];
389 /** One raw1394 handle for each pthread/port
392 static raw1394handle_t raw1394service_handle
[4];
394 /** The service thread that polls raw1394 for new events.
397 static void* raw1394_service( void *arg
)
399 raw1394handle_t handle
= (raw1394handle_t
) arg
;
400 struct pollfd raw1394_poll
;
401 raw1394_poll
.fd
= raw1394_get_fd( handle
);
402 raw1394_poll
.events
= POLLIN
;
403 raw1394_poll
.revents
= 0;
406 if ( poll( &raw1394_poll
, 1, 200) > 0 )
408 if ( (raw1394_poll
.revents
& POLLIN
)
409 || (raw1394_poll
.revents
& POLLPRI
) )
410 raw1394_loop_iterate( handle
);
412 pthread_testcancel();
418 /** Start the raw1394 service threads for handling bus reset.
420 One thread is launched per port on the system.
423 void raw1394_start_service_threads( void )
426 for ( port
= 0; port
< raw1394_get_num_ports(); port
++ )
428 raw1394service_handle
[port
] = raw1394_open( port
);
429 raw1394_set_bus_reset_handler( raw1394service_handle
[port
], reset_handler
);
430 pthread_create( &(raw1394service_thread
[port
]), NULL
, raw1394_service
, raw1394service_handle
[port
] );
432 for ( ; port
< 4; port
++ )
433 raw1394service_handle
[port
] = NULL
;
436 /** Shutdown all the raw1394 service threads.
439 void raw1394_stop_service_threads( void )
442 for ( i
= 0; i
< 4; i
++ )
444 if ( raw1394service_handle
[i
] != NULL
)
446 pthread_cancel( raw1394service_thread
[i
] );
447 pthread_join( raw1394service_thread
[i
], NULL
);
448 raw1394_close( raw1394service_handle
[i
] );