vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / radeon / RadeonAddOn.cpp
blobb763bdbf132196961965cc0b810bfd32ba752089
1 /******************************************************************************
3 / File: RadeonAddOn.cpp
5 / Description: ATI Radeon Video Capture Media AddOn for BeOS.
7 / Copyright 2001, Carlos Hasan
9 *******************************************************************************/
11 #include <support/Autolock.h>
12 #include <media/MediaFormats.h>
13 #include <Directory.h>
14 #include <Entry.h>
15 #include <Debug.h>
16 #include <File.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
22 #include <storage/FindDirectory.h>
23 #include <String.h>
25 #include "RadeonAddOn.h"
26 #include "RadeonProducer.h"
28 #define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
30 CRadeonPlug::CRadeonPlug( CRadeonAddOn *aaddon, const BPath &adev_path, int aid )
31 : addon( aaddon ), dev_path( adev_path ), id( aid ), node( NULL )
33 fFlavorInfo.name = const_cast<char *>("Radeon In");
34 fFlavorInfo.info = const_cast<char *>("Radeon Video In Media Node");
35 fFlavorInfo.kinds = B_BUFFER_PRODUCER | B_CONTROLLABLE | B_PHYSICAL_INPUT;
36 fFlavorInfo.flavor_flags = 0;
37 fFlavorInfo.internal_id = aid;
38 fFlavorInfo.possible_count = 1;
40 fFlavorInfo.in_format_count = 0;
41 fFlavorInfo.in_format_flags = 0;
42 fFlavorInfo.in_formats = NULL;
44 fFlavorInfo.out_format_count = 4;
45 //fFlavorInfo.out_format_count = 1;
46 fFlavorInfo.out_format_flags = 0;
48 fMediaFormat[0].type = B_MEDIA_RAW_VIDEO;
49 fMediaFormat[0].u.raw_video = media_raw_video_format::wildcard;
50 fMediaFormat[0].u.raw_video.interlace = 1;
51 fMediaFormat[0].u.raw_video.display.format = B_RGB32;
53 fMediaFormat[1].type = B_MEDIA_RAW_VIDEO;
54 fMediaFormat[1].u.raw_video = media_raw_video_format::wildcard;
55 fMediaFormat[1].u.raw_video.interlace = 1;
56 fMediaFormat[1].u.raw_video.display.format = B_RGB16;
58 fMediaFormat[2].type = B_MEDIA_RAW_VIDEO;
59 fMediaFormat[2].u.raw_video = media_raw_video_format::wildcard;
60 fMediaFormat[2].u.raw_video.interlace = 1;
61 fMediaFormat[2].u.raw_video.display.format = B_RGB15;
63 fMediaFormat[3].type = B_MEDIA_RAW_VIDEO;
64 fMediaFormat[3].u.raw_video = media_raw_video_format::wildcard;
65 fMediaFormat[3].u.raw_video.interlace = 1;
66 fMediaFormat[3].u.raw_video.display.format = B_YCbCr422;
68 /*fMediaFormat[0].type = B_MEDIA_RAW_VIDEO;
69 fMediaFormat[0].u.raw_video = media_raw_video_format::wildcard;
70 fMediaFormat[0].u.raw_video.interlace = 1;
71 fMediaFormat[0].u.raw_video.display.format = B_YCbCr422;*/
73 fFlavorInfo.out_formats = fMediaFormat;
75 readSettings();
78 BPath
79 CRadeonPlug::getSettingsPath()
81 BPath path;
83 if( find_directory( B_USER_CONFIG_DIRECTORY, &path ) != B_OK )
84 return BPath();
86 path.Append( "settings/Media/RadeonIn" );
88 create_directory( path.Path(), 755 );
90 BString id_string;
92 id_string << "settings" << id;
94 path.Append( id_string.String() );
96 return path;
99 void
100 CRadeonPlug::writeSettings( BMessage *new_settings )
102 BMessage cur_settings;
104 // if new_settings are provided, use them; else, ask node for settings
105 // (needed during shutdown where node cannot reply anymore)
106 if( new_settings != NULL ) {
107 cur_settings = *new_settings;
109 } else {
110 if( node == NULL )
111 return;
113 if( addon->GetConfigurationFor( node, &cur_settings ) != B_OK )
114 return;
117 BMallocIO old_settings_flat, new_settings_flat;
119 settings.Flatten( &old_settings_flat );
120 cur_settings.Flatten( &new_settings_flat );
122 if( old_settings_flat.BufferLength() == new_settings_flat.BufferLength() &&
123 memcmp( old_settings_flat.Buffer(), new_settings_flat.Buffer(), old_settings_flat.BufferLength() ) == 0 )
124 return;
126 settings = cur_settings;
128 BPath settings_path = getSettingsPath();
130 BFile file( settings_path.Path(), B_WRITE_ONLY | B_CREATE_FILE );
132 settings.Flatten( &file );
135 void
136 CRadeonPlug::readSettings()
138 BPath settings_path = getSettingsPath();
140 BFile file( settings_path.Path(), B_READ_ONLY );
142 settings.Unflatten( &file );
146 CRadeonAddOn::CRadeonAddOn(image_id imid)
147 : BMediaAddOn(imid),
148 settings_thread( -1 ), settings_thread_sem( -1 )
150 DPRINT(("CRadeonAddOn::CRadeonAddOn()\n"));
152 fInitStatus = B_NO_INIT;
154 if( RecursiveScan( "/dev/video/radeon" ) != B_OK )
155 return;
157 if( (settings_thread_sem = create_sem( 0, "Radeon In settings" )) < 0 )
158 return;
160 if( INIT_BEN( plug_lock, "Radeon device list" ) < 0 )
161 return;
163 if( (settings_thread = spawn_thread(
164 settings_writer, "Radeon In settings", B_LOW_PRIORITY, this )) < 0 )
165 return;
167 resume_thread( settings_thread );
169 fInitStatus = B_OK;
172 CRadeonAddOn::~CRadeonAddOn()
174 status_t dummy;
176 DPRINT(("CRadeonAddOn::~CRadeonAddOn()\n"));
178 release_sem( settings_thread_sem );
179 wait_for_thread( settings_thread, &dummy );
181 delete_sem( settings_thread_sem );
183 for( int32 i = 0; i < fDevices.CountItems(); ++i ) {
184 CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt(i);
186 delete plug;
189 DELETE_BEN( plug_lock );
193 status_t
194 CRadeonAddOn::InitCheck(const char **out_failure_text)
196 DPRINT(("CRadeonAddOn::InitCheck()\n"));
198 if (fInitStatus < B_OK) {
199 *out_failure_text = "Unknown error";
200 return fInitStatus;
203 return B_OK;
206 int32
207 CRadeonAddOn::settings_writer( void *param )
209 ((CRadeonAddOn *)param)->settingsWriter();
210 return B_OK;
213 void
214 CRadeonAddOn::writeSettings()
216 ACQUIRE_BEN( plug_lock );
218 for( int32 i = 0; i < fDevices.CountItems(); ++i ) {
219 CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt(i);
221 plug->writeSettings( NULL );
224 RELEASE_BEN( plug_lock );
227 void
228 CRadeonAddOn::settingsWriter()
230 while( acquire_sem_etc( settings_thread_sem, 1, B_RELATIVE_TIMEOUT, 10000000 ) == B_TIMED_OUT ) {
231 writeSettings();
235 void
236 CRadeonAddOn::UnregisterNode( BMediaNode *node, BMessage *settings )
238 ACQUIRE_BEN( plug_lock );
240 for( int32 i = 0; i < fDevices.CountItems(); ++i ) {
241 CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt(i);
243 if( plug->getNode() == node ) {
244 // write last settings, so they don't get lost
245 plug->writeSettings( settings );
246 plug->setNode( NULL );
247 break;
251 RELEASE_BEN( plug_lock );
254 int32
255 CRadeonAddOn::CountFlavors()
257 DPRINT(("CRadeonAddOn::CountFlavors()\n"));
259 if (fInitStatus < B_OK)
260 return fInitStatus;
262 return fDevices.CountItems();
266 * The pointer to the flavor received only needs to be valid between
267 * successive calls to BCRadeonAddOn::GetFlavorAt().
269 status_t
270 CRadeonAddOn::GetFlavorAt(int32 n, const flavor_info **out_info)
272 DPRINT(("CRadeonAddOn::GetFlavorAt()\n"));
274 if (fInitStatus < B_OK)
275 return fInitStatus;
277 if (n < 0 || n >= fDevices.CountItems() )
278 return B_BAD_INDEX;
280 /* Return the flavor defined in the constructor */
281 *out_info = ((CRadeonPlug *)fDevices.ItemAt(n))->getFlavorInfo();
282 return B_OK;
285 BMediaNode *
286 CRadeonAddOn::InstantiateNodeFor(
287 const flavor_info *info, BMessage *config, status_t *out_error)
289 DPRINT(("CRadeonAddOn::InstantiateNodeFor()\n"));
291 CRadeonProducer *node;
293 if (fInitStatus < B_OK)
294 return NULL;
296 if (info->internal_id < 0 || info->internal_id >= fDevices.CountItems())
297 return NULL;
299 CRadeonPlug *plug = (CRadeonPlug *)fDevices.ItemAt( info->internal_id );
301 ACQUIRE_BEN( plug_lock );
303 if( plug->getNode() != NULL ) {
304 *out_error = B_BUSY;
305 node = NULL;
307 } else {
308 BMessage single_settings;
310 // under R5, configuration is always an empty message, so we need to
311 // get our own configuration
312 if( config == NULL || 1 )
313 config = plug->getSettings();
315 node = new CRadeonProducer( this, plug->getName(),
316 plug->getDeviceName(), info->internal_id, config );
318 if (node && (node->InitCheck() < B_OK)) {
319 *out_error = node->InitCheck();
320 delete node;
321 node = NULL;
325 plug->setNode( node );
327 RELEASE_BEN( plug_lock );
329 return node;
332 status_t CRadeonAddOn::GetConfigurationFor(
333 BMediaNode *your_node,
334 BMessage *into_message )
336 port_id reply_port;
337 CRadeonProducer::configuration_msg msg;
338 status_t res;
340 reply_port = create_port( 1, "GetConfiguration Reply" );
341 if( reply_port < 0 )
342 return reply_port;
344 msg.reply_port = reply_port;
346 res = write_port_etc( your_node->ControlPort(), CRadeonProducer::C_GET_CONFIGURATION,
347 &msg, sizeof( msg ), B_TIMEOUT, 10000000 );
348 if( res == B_OK ) {
349 ssize_t reply_size;
350 CRadeonProducer::configuration_msg_reply *reply;
351 int32 code;
353 reply_size = port_buffer_size_etc( reply_port, B_TIMEOUT, 10000000 );
354 if( reply_size < 0 )
355 res = reply_size;
356 else {
357 reply = (CRadeonProducer::configuration_msg_reply *)malloc( reply_size );
359 res = read_port( reply_port, &code, reply, reply_size );
360 if( res == reply_size ) {
361 if( code != CRadeonProducer::C_GET_CONFIGURATION_REPLY )
362 res = B_ERROR;
363 else {
364 res = reply->res;
366 if( res == B_OK )
367 res = into_message->Unflatten( &reply->config );
371 free( reply );
375 delete_port( reply_port );
377 return res;
380 status_t
381 CRadeonAddOn::RecursiveScan(const char* rootPath, BEntry *rootEntry = NULL)
383 BDirectory root;
385 if( rootEntry != NULL )
386 root.SetTo( rootEntry );
387 else if( rootPath != NULL ) {
388 root.SetTo( rootPath );
389 } else {
390 PRINT(("Error in MultiAudioAddOn::RecursiveScan null params\n"));
391 return B_ERROR;
394 BEntry entry;
395 int cur_id = 0;
397 while( root.GetNextEntry( &entry ) > B_ERROR ) {
398 if(entry.IsDirectory()) {
399 RecursiveScan( rootPath, &entry );
401 } else {
402 BPath path;
404 entry.GetPath(&path);
406 CRadeon device( path.Path() );
408 if( device.InitCheck() != B_OK)
409 continue;
411 CVIPPort vip_port( device );
413 // if there is a Rage Theatre, then there should be Video-In
414 if( vip_port.InitCheck() == B_OK &&
415 ((vip_port.FindVIPDevice( C_THEATER100_VIP_DEVICE_ID ) >= 0)
416 || (vip_port.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID ) >= 0)))
418 fDevices.AddItem( new CRadeonPlug( this, path, cur_id++ ));
423 return B_OK;
427 BMediaAddOn *
428 make_media_addon(image_id imid)
430 return new CRadeonAddOn(imid);