Example #1
0
Settings::~Settings()
{
	// only save the settings if something has changed
	if (!fUpdated)
		return;

	BFile file;
	if (Open(&file, B_CREATE_FILE | B_WRITE_ONLY) != B_OK)
		return;

	disk_probe_settings settings;

	settings.window_frame = fMessage.FindRect("window_frame");
#if B_HOST_IS_BENDIAN
	// settings are saved in little endian
	settings.window_frame.left = B_HOST_TO_LENDIAN_FLOAT(
		settings.window_frame.left);
	settings.window_frame.top = B_HOST_TO_LENDIAN_FLOAT(
		settings.window_frame.top);
	settings.window_frame.right = B_HOST_TO_LENDIAN_FLOAT(
		settings.window_frame.right);
	settings.window_frame.bottom = B_HOST_TO_LENDIAN_FLOAT(
		settings.window_frame.bottom);
#endif

	settings.base_type = B_HOST_TO_LENDIAN_INT32(
		fMessage.FindInt32("base_type"));
	settings.font_size = B_HOST_TO_LENDIAN_INT32(
		int32(fMessage.FindFloat("font_size") + 0.5f));
	settings.flags = B_HOST_TO_LENDIAN_INT32(
		(fMessage.FindBool("case_sensitive") ? kCaseSensitive : 0)
		| (fMessage.FindInt8("find_mode") == kHexMode ? kHexFindMode : 0));

	file.Write(&settings, sizeof(settings));
}
Example #2
0
void MMFlattenMessage(const MMessage * msg, void * outBuf)
{
   /* Format:  0. Protocol revision number (4 bytes, always set to CURRENT_PROTOCOL_VERSION) */
   /*          1. 'what' code (4 bytes)                                                      */
   /*          2. Number of entries (4 bytes)                                                */
   /*          3. Entry name length (4 bytes)                                                */
   /*          4. Entry name string (flattened String)                                       */
   /*          5. Entry type code (4 bytes)                                                  */
   /*          6. Entry data length (4 bytes)                                                */
   /*          7. Entry data (n bytes)                                                       */
   /*          8. loop to 3 as necessary                                                     */

   /* Write current protocol version */
   uint32 writeOffset = 0;
   {
      uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(CURRENT_PROTOCOL_VERSION);
      WriteData(outBuf, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
   }

   /* Write 'what' code */
   {
      uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(msg->what);
      WriteData(outBuf, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
   }

   /* Calculate the number of flattenable entries (may be less than the total number of entries!) */
   {
      uint32 numFlattenableEntries = 0;
      {
         const MMessageField * f = msg->firstField;
         while(f)
         {
            if (f->isFlattenable) numFlattenableEntries++;
            f = f->nextField;
         }
      }

      /* Write number of entries */
      {
         uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(numFlattenableEntries);
         WriteData(outBuf, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
      }

      /* Write entries */
      {
         const MMessageField * f = msg->firstField;
         while(f)
         {
            if (f->isFlattenable) writeOffset += FlattenMMessageField(f, &((char *)outBuf)[writeOffset]);
            f = f->nextField;
         }
      }
   }
/*printf("%s "UINT32_FORMAT_SPEC"/"UINT32_FORMAT_SPEC"\n", (writeOffset != MMGetFlattenedSize(msg))?"ERROR":"ok", writeOffset, MMGetFlattenedSize(msg)); DEBUG */
}
Example #3
0
int32 PacketizedProxyDataIO :: Write(const void * buffer, uint32 size)
{
   if (size > _maxTransferUnit)
   {
      LogTime(MUSCLE_LOG_ERROR, "PacketizedProxyDataIO:  Error, tried to send packet with size " UINT32_FORMAT_SPEC ", max transfer unit is set to " UINT32_FORMAT_SPEC "\n", size, _maxTransferUnit);
      return -1;
   }

   // Only accept more data if we are done sending the data we already have buffered up
   bool tryAgainAfter = false;
   int32 ret = 0;
   if (HasBufferedOutput()) tryAgainAfter = true;
   else
   {
      // No data buffered?
      _outputBufferBytesSent = 0;

      if (_outputBuffer.SetNumBytes(sizeof(uint32)+size, false) != B_NO_ERROR) return 0;
      muscleCopyOut(_outputBuffer.GetBuffer(), B_HOST_TO_LENDIAN_INT32(size));
      memcpy(_outputBuffer.GetBuffer()+sizeof(uint32), buffer, size);
      ret = size;
   }

   if (WriteBufferedOutputAux() != B_NO_ERROR) return -1;

   return ((tryAgainAfter)&&(HasBufferedOutput() == false)) ? Write(buffer, size) : ret;
}
Example #4
0
void 
PCL6Writer::Append(uint32 value)
{
	int32 v = B_HOST_TO_LENDIAN_INT32(value);
	Append(BYTE_AT(v, 0));  
	Append(BYTE_AT(v, 1));  
	Append(BYTE_AT(v, 2));  
	Append(BYTE_AT(v, 3));  
}
Example #5
0
uint16
Volume::_GroupCheckSum(ext2_block_group *group, int32 index)
{
	uint16 checksum = 0;
	if (HasChecksumFeature()) {
		int32 number = B_HOST_TO_LENDIAN_INT32(index);
		checksum = calculate_crc(0xffff, fSuperBlock.uuid,
			sizeof(fSuperBlock.uuid));
		checksum = calculate_crc(checksum, (uint8*)&number, sizeof(number));
		checksum = calculate_crc(checksum, (uint8*)group, 30);
		if (Has64bitFeature()) {
			checksum = calculate_crc(checksum, (uint8*)group + 34, 
				fGroupDescriptorSize - 34);
		}
	}
	return checksum;
}
Example #6
0
void
MemoryView::_GetNextHexBlock(char* buffer, int32 bufferSize,
	const char* address)
{
	switch(fHexMode) {
		case HexMode8BitInt:
		{
			snprintf(buffer, bufferSize, "%02" B_PRIx8,
				*((const uint8*)address));
			break;
		}
		case HexMode16BitInt:
		{
			uint16 data = *((const uint16*)address);
			switch(fCurrentEndianMode)
			{
				case EndianModeBigEndian:
				{
					data = B_HOST_TO_BENDIAN_INT16(data);
				}
				break;

				case EndianModeLittleEndian:
				{
					data = B_HOST_TO_LENDIAN_INT16(data);
				}
				break;
			}
			snprintf(buffer, bufferSize, "%04" B_PRIx16,
				data);
			break;
		}
		case HexMode32BitInt:
		{
			uint32 data = *((const uint32*)address);
			switch(fCurrentEndianMode)
			{
				case EndianModeBigEndian:
				{
					data = B_HOST_TO_BENDIAN_INT32(data);
				}
				break;

				case EndianModeLittleEndian:
				{
					data = B_HOST_TO_LENDIAN_INT32(data);
				}
				break;
			}
			snprintf(buffer, bufferSize, "%08" B_PRIx32,
				data);
			break;
		}
		case HexMode64BitInt:
		{
			uint64 data = *((const uint64*)address);
			switch(fCurrentEndianMode)
			{
				case EndianModeBigEndian:
				{
					data = B_HOST_TO_BENDIAN_INT64(data);
				}
				break;

				case EndianModeLittleEndian:
				{
					data = B_HOST_TO_LENDIAN_INT64(data);
				}
				break;
			}
			snprintf(buffer, bufferSize, "%0*" B_PRIx64,
				16, data);
			break;
		}
	}
}
int32 PacketTunnelIOGateway :: DoOutputImplementation(uint32 maxBytes)
{
   if (_outputPacketBuffer.SetNumBytes(_maxTransferUnit, false) != B_NO_ERROR) return -1;

   uint32 totalBytesWritten = 0;
   bool firstTime = true;
   while((totalBytesWritten < maxBytes)&&((firstTime)||(IsSuggestedTimeSliceExpired() == false)))
   {
      firstTime = false;

      // Step 1:  Add as much data to our output packet buffer as we can fit into it
      while((_outputPacketSize+FRAGMENT_HEADER_SIZE < _maxTransferUnit)&&(HasBytesToOutput()))
      {
         // Demand-create the next send-buffer
         if (_currentOutputBuffer() == NULL)
         {
            MessageRef msg;
            if (GetOutgoingMessageQueue().RemoveHead(msg) == B_NO_ERROR)
            {
               _currentOutputBufferOffset = 0; 
               _currentOutputBuffer.Reset();

               if (_slaveGateway())
               {
                  DataIORef oldIO = _slaveGateway()->GetDataIO(); // save slave gateway's old state

                  // Get the slave gateway to generate its output into our ByteBuffer
                  _fakeSendBuffer.SetNumBytes(0, false);
                  _fakeSendIO.Seek(0, SeekableDataIO::IO_SEEK_SET);
                  _slaveGateway()->SetDataIO(DataIORef(&_fakeSendIO, false));
                  _slaveGateway()->AddOutgoingMessage(msg);
                  while(_slaveGateway()->DoOutput() > 0) {/* empty */}

                  _slaveGateway()->SetDataIO(oldIO);  // restore slave gateway's old state
                  _currentOutputBuffer.SetRef(&_fakeSendBuffer, false);
               }
               else if (_fakeSendBuffer.SetNumBytes(msg()->FlattenedSize(), false) == B_NO_ERROR)
               {
                  // Default algorithm:  Just flatten the Message into the buffer
                  msg()->Flatten(_fakeSendBuffer.GetBuffer());
                  _currentOutputBuffer.SetRef(&_fakeSendBuffer, false);
               }
            }
         }
         if (_currentOutputBuffer() == NULL) break;   // oops, out of mem?

         uint32 sbSize          = _currentOutputBuffer()->GetNumBytes();
         uint32 dataBytesToSend = muscleMin(_maxTransferUnit-(_outputPacketSize+FRAGMENT_HEADER_SIZE), sbSize-_currentOutputBufferOffset);

         uint8 * p = _outputPacketBuffer.GetBuffer()+_outputPacketSize;
         muscleCopyOut(&p[0*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_magic));                      // a well-known magic number, for sanity checking
         muscleCopyOut(&p[1*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_sexID));                      // source exclusion ID
         muscleCopyOut(&p[2*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_sendMessageIDCounter));       // message ID tag so the receiver can track what belongs where
         muscleCopyOut(&p[3*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(_currentOutputBufferOffset));  // start offset (within its message) for this sub-chunk
         muscleCopyOut(&p[4*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(dataBytesToSend)); // size of this sub-chunk
         muscleCopyOut(&p[5*sizeof(uint32)], B_HOST_TO_LENDIAN_INT32(sbSize));          // total size of this message
//printf("CREATING PACKET magic=" UINT32_FORMAT_SPEC " msgID=" UINT32_FORMAT_SPEC " offset=" UINT32_FORMAT_SPEC " chunkSize=" UINT32_FORMAT_SPEC " totalSize=" UINT32_FORMAT_SPEC "\n", _magic, _sendMessageIDCounter, _currentOutputBufferOffset, dataBytesToSend, sbSize);
         memcpy(p+FRAGMENT_HEADER_SIZE, _currentOutputBuffer()->GetBuffer()+_currentOutputBufferOffset, dataBytesToSend);

         _outputPacketSize += (FRAGMENT_HEADER_SIZE+dataBytesToSend);
         _currentOutputBufferOffset += dataBytesToSend;
         if (_currentOutputBufferOffset == sbSize)
         {
            _currentOutputBuffer.Reset();
            _fakeSendBuffer.Clear(_fakeSendBuffer.GetNumBytes() > MAX_CACHE_SIZE);  // don't keep too much memory around!
            _sendMessageIDCounter++;
         }
      }

      // Step 2:  If we have a non-empty packet to send, send it!
      if (_outputPacketSize > 0)
      {
         // If bytesWritten is set to zero, we just hold this buffer until our next call.
         int32 bytesWritten = GetDataIO()()->Write(_outputPacketBuffer.GetBuffer(), _outputPacketSize);
//printf("WROTE " INT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " bytes %s\n", bytesWritten, _outputPacketSize, (bytesWritten==(int32)_outputPacketSize)?"":"******** SHORT ***********");
         if (bytesWritten > 0)
         {
            if (bytesWritten != (int32)_outputPacketSize) LogTime(MUSCLE_LOG_ERROR, "PacketTunnelIOGateway::DoOutput():  Short write!  (" INT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " bytes)\n", bytesWritten, _outputPacketSize);
            _outputPacketBuffer.Clear();
            _outputPacketSize = 0;
            totalBytesWritten += bytesWritten;
         }
         else if (bytesWritten == 0) break;  // no more space to write, for now
         else return -1;
      }
      else break;  // nothing more to do! 
   }
   return totalBytesWritten;
}
Example #8
0
bool TRIFFWriter::InitAVIFile()
{	
	
	//	We cannot write out if all elements are not initialized...
	
	off_t	savePos;	
	bool 	retVal 	= true;
	ssize_t size 	= 0x4949;
	
	//	Rewind the file
	m_File->Seek(0, SEEK_SET);
		
	//	Write RIFF header
	WriteRIFFChunk(size);
	
	//	Write AVIHeader LIST chunk
	retVal = WriteLISTChunk(size);
	if (retVal == false)
		return retVal;
	
	//	Save position for later calculation.  Back over size...
	off_t listHeaderPos = m_File->Position();
	listHeaderPos -= sizeof(uint32);

	WriteIntMsb(m_File, kRiff_hdrl_Chunk, sizeof(uint32)); 	

	//	Write AVIHeader chunk
	retVal = WriteavihChunk();
	if (retVal == false)
		return retVal;
	
	//
	//	Write stream data List Chunk
	//
	
	//	Make sure we have streams to write
	if ( (m_StreamCount == 0) || (m_StreamCount > kRiffWriteMaxStreams) )
		return false;
	
	//
	//	Write out first stream
	//
		
	retVal = WriteLISTChunk(size);
	if (retVal == false)
		return retVal;
			
	//	Save position for later size calculation
	off_t streamOnePos = m_File->Position();

	//	Write out 'strl' chunk
	WriteIntMsb(m_File, kRiff_strl_Chunk, sizeof(uint32));
		
	//	First stream header
	retVal = WriteStreamHeader(&m_StreamHeaderOne);
	
	//	First stream format
	retVal = WriteStreamFormat(&m_StreamHeaderOne);
	
	//	Update streamOne chunk size
	savePos = m_File->Position();
	uint32 streamOneSize = (uint32)(savePos - streamOnePos);
	
	//	Update list header chunk size
	B_HOST_TO_LENDIAN_INT32(streamOneSize);
	streamOnePos -= sizeof(uint32);
	m_File->WriteAt(streamOnePos, &streamOneSize, sizeof(uint32));
	
	//	Return to saved postion
	m_File->Seek(savePos, SEEK_SET);
	
	//
	//	Write out second stream
	//
	
	if (m_StreamCount == 2)
	{
		retVal = WriteLISTChunk(size);
		if (retVal == false)
			return retVal;
	
		//	Save position for later size calculation
		off_t streamTwoPos = m_File->Position();

		//	Write out 'strl' chunk
		WriteIntMsb(m_File, kRiff_strl_Chunk, sizeof(uint32)); 	
		
		//	Second stream header
		retVal = WriteStreamHeader(&m_StreamHeaderTwo);
		
		//	Second stream format
		retVal = WriteStreamFormat(&m_StreamHeaderTwo);
		
		//	Update streamTwo chunk size
		savePos = m_File->Position();
		uint32 streamTwoSize = savePos - streamTwoPos;
		
		//	Update list header chunk size
		B_HOST_TO_LENDIAN_INT32(streamTwoSize);
		streamTwoPos -= sizeof(uint32);
		m_File->WriteAt(streamTwoPos, &streamTwoSize, sizeof(uint32));
		
		//	Restore position
		m_File->Seek(savePos, SEEK_SET);
	}
			
	//	Save position and go back and update unitialized chunk sizes
	savePos = m_File->Position();
	uint32 listHeaderSize = savePos - listHeaderPos;
	
	//	Update list header chunk size
	B_HOST_TO_LENDIAN_INT32(listHeaderSize);
	m_File->WriteAt(listHeaderPos, &listHeaderSize, sizeof(uint32));
	
	//	Restore position
	m_File->Seek(savePos, SEEK_SET);
	
	//
	//	Write movi Chunk.  We don't know the true size yet...
	//
	
	retVal = WriteLISTChunk(size);
	if (retVal == false)
		return retVal;
		
	WriteIntMsb(m_File, kRiff_movi_Chunk, sizeof(uint32)); 	
	
	//	Save offset for later index chunk calculation
	m_MoviChunkOffset = m_File->Position();
	
	//	All done
	return retVal;
	
}
Example #9
0
bool TRIFFWriter::CompleteAVIFile()
{
	bool 	retVal = true;
	uint32 	streamSize;
	
	//	Save our position
	off_t savePos = m_File->Position();
	
	//	Rewind
	m_File->Seek(0, SEEK_SET);
					
	//	Skip over RIFF form
	m_File->Seek(sizeof(uint32), SEEK_CUR);
	
	//	Write file size and bump pointer
	off_t fileSize;
	m_File->GetSize(&fileSize);
	uint32 size = (uint32)fileSize;		
	B_HOST_TO_LENDIAN_INT32(size);
	m_File->WriteAt(m_File->Position(), &size, sizeof(uint32));
	m_File->Seek( sizeof(uint32), SEEK_CUR);
	
	//	Skip AVI form, LIST chunk and hdrl chunk
	m_File->Seek( sizeof(uint32) * 6, SEEK_CUR);
	
	//
	//	Update unitialized AVIHeader fields
	//
			
	//	Skip filled fields and update fields needing info
	m_File->Seek( sizeof(uint32) * 4, SEEK_CUR);
	WriteAtIntLsb(m_File, m_TotalFrames, sizeof(uint32));
	m_File->Seek( sizeof(uint32), SEEK_CUR);
	m_File->Seek( sizeof(uint32) * 8, SEEK_CUR);
	WriteAtIntLsb(m_File, m_TotalFrames, sizeof(uint32));
	m_File->Seek( sizeof(uint32), SEEK_CUR);
	
	//
	//	Update unitialized stream header and format fields
	//	
	
	//	The first should always be the video stream
	
	//	Skip LIST chunk
	m_File->Seek( sizeof(uint32) * 3, SEEK_CUR);
	
	//	Skip stream header chunkID and size
	m_File->Seek( sizeof(uint32) * 2, SEEK_CUR);
	
	//	Skip filled fields and update DataLength.  Skip over rest of chunk...
	m_File->Seek( sizeof(uint32) * 8, SEEK_CUR);
	WriteAtIntLsb(m_File, m_TotalFrames, sizeof(uint32));
	m_File->Seek( sizeof(uint32) * 4, SEEK_CUR);
	
	//	Skip vids StreamFormat chunk
	m_File->Seek( sizeof(uint32), SEEK_CUR);	
	m_File->Read( &streamSize, sizeof(uint32));
	m_File->Seek(streamSize, SEEK_CUR);
	
	//	Is there an audio chunk to update?  If so, it will always be the second stream
	if ( m_StreamCount > 1)
	{
		//	Skip LIST chunk
		m_File->Seek( sizeof(uint32) * 3, SEEK_CUR);
	
		//	Skip stream header
		m_File->Seek( sizeof(uint32), SEEK_CUR);
		m_File->Read( &streamSize, sizeof(uint32));
		m_File->Seek(streamSize, SEEK_CUR);

		//	Skip stream format header and size
		m_File->Seek( sizeof(uint32) * 2, SEEK_CUR);

		//	Skip filled fields and update ByteCount
		m_File->Seek( 28, SEEK_CUR);
		WriteAtIntLsb(m_File, m_AUDSHeader.ByteCount, sizeof(uint32));
		m_File->Seek( sizeof(uint32), SEEK_CUR);		
	}
	
	//
	//	Write out size of 'movi' chunk
	//
	
	//	Seek to start of 'movi' index
	off_t seekPos = m_MoviChunkOffset - ( sizeof(uint32) * 2);
	m_File->Seek(seekPos, SEEK_SET);
	
	//	Calculate movi chunk size and write it out
	m_File->GetSize(&fileSize);
	size = (uint32)fileSize;
	uint32 moviChunkSize = size - m_MoviChunkOffset;
	moviChunkSize += sizeof(uint32);
	WriteAtIntLsb(m_File, moviChunkSize, sizeof(uint32));
	m_File->Seek( sizeof(uint32), SEEK_CUR);
				
	//	Go to end of file and write out index chunk
	m_File->Seek(0, SEEK_END);
	retVal = Writeidx1Chunk();
	
	return retVal;

}
Example #10
0
status_t
pll_set(display_mode* mode, uint8 crtcID)
{
	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
	pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
	uint32 dp_clock = gConnector[connectorIndex]->dpInfo.linkRate;
	bool ssEnabled = false;

	pll->pixelClock = mode->timing.pixel_clock;

	radeon_shared_info &info = *gInfo->shared_info;

	// Probe for PLL spread spectrum info;
	pll->ssPercentage = 0;
	pll->ssType = 0;
	pll->ssStep = 0;
	pll->ssDelay = 0;
	pll->ssRange = 0;
	pll->ssReferenceDiv = 0;

	switch (display_get_encoder_mode(connectorIndex)) {
		case ATOM_ENCODER_MODE_DP_MST:
		case ATOM_ENCODER_MODE_DP:
			if (info.dceMajor >= 4)
				pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_DP);
			else {
				if (dp_clock == 162000) {
					ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID2);
					if (!ssEnabled)
						// id2 failed, try id1
						ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
				} else
					ssEnabled = pll_ppll_ss_probe(pll, ATOM_DP_SS_ID1);
			}
			break;
		case ATOM_ENCODER_MODE_LVDS:
			if (info.dceMajor >= 4)
				ssEnabled = pll_asic_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
			else
				ssEnabled = pll_ppll_ss_probe(pll, gInfo->lvdsSpreadSpectrumID);
			break;
		case ATOM_ENCODER_MODE_DVI:
			if (info.dceMajor >= 4)
				ssEnabled = pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_TMDS);
			break;
		case ATOM_ENCODER_MODE_HDMI:
			if (info.dceMajor >= 4)
				ssEnabled = pll_asic_ss_probe(pll, ASIC_INTERNAL_SS_ON_HDMI);
			break;
	}

	pll_setup_flags(pll, crtcID);
		// set up any special flags
	pll_adjust(pll, mode, crtcID);
		// get any needed clock adjustments, set reference/post dividers
	pll_compute(pll);
		// compute dividers

	display_crtc_ss(pll, ATOM_DISABLE);
		// disable ss

	uint8 tableMajor;
	uint8 tableMinor;

	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
	atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor);

	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
		tableMajor, tableMinor);

	uint32 bitsPerColor = 8;
		// TODO: Digital Depth, EDID 1.4+ on digital displays
		// isn't in Haiku edid common code?

	// Prepare arguments for AtomBIOS call
	union setPixelClock {
		SET_PIXEL_CLOCK_PS_ALLOCATION base;
		PIXEL_CLOCK_PARAMETERS v1;
		PIXEL_CLOCK_PARAMETERS_V2 v2;
		PIXEL_CLOCK_PARAMETERS_V3 v3;
		PIXEL_CLOCK_PARAMETERS_V5 v5;
		PIXEL_CLOCK_PARAMETERS_V6 v6;
	};
	union setPixelClock args;
	memset(&args, 0, sizeof(args));

	switch (tableMinor) {
		case 1:
			args.v1.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v1.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv);
			args.v1.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v1.ucFracFbDiv = pll->feedbackDivFrac;
			args.v1.ucPostDiv = pll->postDiv;
			args.v1.ucPpll = pll->id;
			args.v1.ucCRTC = crtcID;
			args.v1.ucRefDivSrc = 1;
			break;
		case 2:
			args.v2.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v2.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv);
			args.v2.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v2.ucFracFbDiv = pll->feedbackDivFrac;
			args.v2.ucPostDiv = pll->postDiv;
			args.v2.ucPpll = pll->id;
			args.v2.ucCRTC = crtcID;
			args.v2.ucRefDivSrc = 1;
			break;
		case 3:
			args.v3.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v3.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv);
			args.v3.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v3.ucFracFbDiv = pll->feedbackDivFrac;
			args.v3.ucPostDiv = pll->postDiv;
			args.v3.ucPpll = pll->id;
			args.v3.ucMiscInfo = (pll->id << 2);
			if (pll->ssPercentage > 0
				&& (pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) {
				args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
			}
			args.v3.ucTransmitterId
				= gConnector[connectorIndex]->encoder.objectID;
			args.v3.ucEncoderMode = display_get_encoder_mode(connectorIndex);
			break;
		case 5:
			args.v5.ucCRTC = crtcID;
			args.v5.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v5.ucRefDiv = pll->referenceDiv;
			args.v5.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v5.ulFbDivDecFrac
				= B_HOST_TO_LENDIAN_INT32(pll->feedbackDivFrac * 100000);
			args.v5.ucPostDiv = pll->postDiv;
			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
			if (pll->ssPercentage > 0
				&& (pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) {
				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
			}
			switch (bitsPerColor) {
				case 8:
				default:
					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
					break;
				case 10:
					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
					break;
			}
			args.v5.ucTransmitterID
				= gConnector[connectorIndex]->encoder.objectID;
			args.v5.ucEncoderMode
				= display_get_encoder_mode(connectorIndex);
			args.v5.ucPpll = pll->id;
			break;
		case 6:
			args.v6.ulDispEngClkFreq
				= B_HOST_TO_LENDIAN_INT32(crtcID << 24 | pll->pixelClock / 10);
			args.v6.ucRefDiv = pll->referenceDiv;
			args.v6.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v6.ulFbDivDecFrac
				= B_HOST_TO_LENDIAN_INT32(pll->feedbackDivFrac * 100000);
			args.v6.ucPostDiv = pll->postDiv;
			args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
			if (pll->ssPercentage > 0
				&& (pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) {
				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
			}
			switch (bitsPerColor) {
				case 8:
				default:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
					break;
				case 10:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
					break;
				case 12:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
					break;
				case 16:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
					break;
			}
			args.v6.ucTransmitterID
				= gConnector[connectorIndex]->encoder.objectID;
			args.v6.ucEncoderMode = display_get_encoder_mode(connectorIndex);
			args.v6.ucPpll = pll->id;
			break;
		default:
			TRACE("%s: ERROR: table version %" B_PRIu8 ".%" B_PRIu8 " TODO\n",
				__func__, tableMajor, tableMinor);
			return B_ERROR;
	}

	TRACE("%s: set adjusted pixel clock %" B_PRIu32 " (was %" B_PRIu32 ")\n",
		__func__, pll->pixelClock, mode->timing.pixel_clock);

	status_t result = atom_execute_table(gAtomContext, index, (uint32*)&args);

	if (ssEnabled)
		display_crtc_ss(pll, ATOM_ENABLE);

	return result;
}
Example #11
0
static inline void UMWriteInt32(uint8 * ptr, uint32 val) {*((uint32 *)ptr) = B_HOST_TO_LENDIAN_INT32(val);}
Example #12
0
void
VideoProducer::NodeRegistered()
{
	if (fInitStatus != B_OK) {
		ReportError(B_NODE_IN_DISTRESS);
		return;
	}

	/* Set up the parameter web */

	//TODO: remove and put sensible stuff there
	BParameterWeb *web = new BParameterWeb();
	BParameterGroup *main = web->MakeGroup(Name());
	BParameterGroup *g;

	/*
	g = main->MakeGroup("Color");
	BDiscreteParameter *state = g->MakeDiscreteParameter(
			P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color");
	state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red");
	state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green");
	state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue");
	*/

	BParameter *p;
	g = main->MakeGroup("Info");
	p = g->MakeTextParameter(
		P_INFO, B_MEDIA_RAW_VIDEO, "", "Info", 256);

	int32 id = P_LAST;
	if (fCamDevice) {
#ifndef SINGLE_PARAMETER_GROUP
		main = web->MakeGroup("Device");
#endif
		fCamDevice->AddParameters(main, id);
		if (fCamDevice->Sensor()) {
#ifndef SINGLE_PARAMETER_GROUP
			main = web->MakeGroup("Sensor");
#endif
			fCamDevice->Sensor()->AddParameters(main, id);
		}
	}

	fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000);
	fLastColorChange = system_time();

	/* After this call, the BControllable owns the BParameterWeb object and
	 * will delete it for you */
	SetParameterWeb(web);

	fOutput.node = Node();
	fOutput.source.port = ControlPort();
	fOutput.source.id = 0;
	fOutput.destination = media_destination::null;
	strcpy(fOutput.name, Name());

	/* Tailor these for the output of your device */
	fOutput.format.type = B_MEDIA_RAW_VIDEO;
	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
	fOutput.format.u.raw_video.interlace = 1;
	fOutput.format.u.raw_video.display.format = B_RGB32;
	fOutput.format.u.raw_video.field_rate = FIELD_RATE; // XXX: mmu

	/* Start the BMediaEventLooper control loop running */
	Run();
}
Example #13
0
status_t
pll_set(uint8 pllID, uint32 pixelClock, uint8 crtcID)
{
	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
	pll_info *pll = &gConnector[connectorIndex]->encoder.pll;

	pll->pixelClock = pixelClock;
	pll->id = pllID;

	pll_setup_flags(pll, crtcID);
		// set up any special flags
	pll_adjust(pll, crtcID);
		// get any needed clock adjustments, set reference/post dividers
	pll_compute(pll);
		// compute dividers

	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
	union set_pixel_clock args;
	memset(&args, 0, sizeof(args));

	uint8 tableMajor;
	uint8 tableMinor;

	atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor);

	uint32 bitsPerChannel = 8;
		// TODO: Digital Depth, EDID 1.4+ on digital displays
		// isn't in Haiku edid common code?

	switch (tableMinor) {
		case 1:
			args.v1.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v1.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv);
			args.v1.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v1.ucFracFbDiv = pll->feedbackDivFrac;
			args.v1.ucPostDiv = pll->postDiv;
			args.v1.ucPpll = pll->id;
			args.v1.ucCRTC = crtcID;
			args.v1.ucRefDivSrc = 1;
			break;
		case 2:
			args.v2.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v2.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv);
			args.v2.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v2.ucFracFbDiv = pll->feedbackDivFrac;
			args.v2.ucPostDiv = pll->postDiv;
			args.v2.ucPpll = pll->id;
			args.v2.ucCRTC = crtcID;
			args.v2.ucRefDivSrc = 1;
			break;
		case 3:
			args.v3.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v3.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv);
			args.v3.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v3.ucFracFbDiv = pll->feedbackDivFrac;
			args.v3.ucPostDiv = pll->postDiv;
			args.v3.ucPpll = pll->id;
			args.v3.ucMiscInfo = (pll->id << 2);
			// if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
			// 	args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
			args.v3.ucTransmitterId
				= gConnector[connectorIndex]->encoder.objectID;
			args.v3.ucEncoderMode = display_get_encoder_mode(connectorIndex);
			break;
		case 5:
			args.v5.ucCRTC = crtcID;
			args.v5.usPixelClock
				= B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10);
			args.v5.ucRefDiv = pll->referenceDiv;
			args.v5.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v5.ulFbDivDecFrac
				= B_HOST_TO_LENDIAN_INT32(pll->feedbackDivFrac * 100000);
			args.v5.ucPostDiv = pll->postDiv;
			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
			// if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
			//	args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
			switch (bitsPerChannel) {
				case 8:
				default:
					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
					break;
				case 10:
					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
					break;
			}
			args.v5.ucTransmitterID
				= gConnector[connectorIndex]->encoder.objectID;
			args.v5.ucEncoderMode
				= display_get_encoder_mode(connectorIndex);
			args.v5.ucPpll = pllID;
			break;
		case 6:
			args.v6.ulDispEngClkFreq
				= B_HOST_TO_LENDIAN_INT32(crtcID << 24 | pll->pixelClock / 10);
			args.v6.ucRefDiv = pll->referenceDiv;
			args.v6.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv);
			args.v6.ulFbDivDecFrac
				= B_HOST_TO_LENDIAN_INT32(pll->feedbackDivFrac * 100000);
			args.v6.ucPostDiv = pll->postDiv;
			args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
			// if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
			//	args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
			switch (bitsPerChannel) {
				case 8:
				default:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
					break;
				case 10:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
					break;
				case 12:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
					break;
				case 16:
					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
					break;
			}
			args.v6.ucTransmitterID
				= gConnector[connectorIndex]->encoder.objectID;
			args.v6.ucEncoderMode = display_get_encoder_mode(connectorIndex);
			args.v6.ucPpll = pllID;
			break;
		default:
			TRACE("%s: ERROR: table version %" B_PRIu8 ".%" B_PRIu8 " TODO\n",
				__func__, tableMajor, tableMinor);
			return B_ERROR;
	}

	TRACE("%s: set adjusted pixel clock %" B_PRIu32 " (was %" B_PRIu32 ")\n",
		__func__, pll->pixelClock, pixelClock);

	return atom_execute_table(gAtomContext, index, (uint32*)&args);
}
Example #14
0
status_t
pll_external_set(uint32 clock)
{
	TRACE("%s: set external pll clock to %" B_PRIu32 "\n", __func__, clock);

	if (clock == 0)
		ERROR("%s: Warning: default display clock is 0?\n", __func__);

	// also known as PLL display engineering
	uint8 tableMajor;
	uint8 tableMinor;

	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
	atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor);

	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
		tableMajor, tableMinor);

	union setPixelClock {
		SET_PIXEL_CLOCK_PS_ALLOCATION base;
		PIXEL_CLOCK_PARAMETERS v1;
		PIXEL_CLOCK_PARAMETERS_V2 v2;
		PIXEL_CLOCK_PARAMETERS_V3 v3;
		PIXEL_CLOCK_PARAMETERS_V5 v5;
		PIXEL_CLOCK_PARAMETERS_V6 v6;
	};
	union setPixelClock args;
	memset(&args, 0, sizeof(args));

	radeon_shared_info &info = *gInfo->shared_info;
	uint32 dceVersion = (info.dceMajor * 100) + info.dceMinor;
	switch (tableMajor) {
		case 1:
			switch(tableMinor) {
				case 5:
					// If the default DC PLL clock is specified,
					// SetPixelClock provides the dividers.
					args.v5.ucCRTC = ATOM_CRTC_INVALID;
					args.v5.usPixelClock = B_HOST_TO_LENDIAN_INT16(clock / 10);
					args.v5.ucPpll = ATOM_DCPLL;
					break;
				case 6:
					// If the default DC PLL clock is specified,
					// SetPixelClock provides the dividers.
					args.v6.ulDispEngClkFreq
						= B_HOST_TO_LENDIAN_INT32(clock / 10);
					if (dceVersion == 601)
						args.v6.ucPpll = ATOM_EXT_PLL1;
					else if (dceVersion >= 600)
						args.v6.ucPpll = ATOM_PPLL0;
					else
						args.v6.ucPpll = ATOM_DCPLL;
					break;
				default:
					ERROR("%s: Unknown table version %" B_PRIu8
						".%" B_PRIu8 "\n", __func__, tableMajor, tableMinor);
			}
			break;
		default:
			ERROR("%s: Unknown table version %" B_PRIu8
						".%" B_PRIu8 "\n", __func__, tableMajor, tableMinor);
	}
	return B_OK;
}
Example #15
0
static uint32 FlattenMMessageField(const MMessageField * f, void * outBuf)
{
   /* 3. Entry name length (4 bytes)          */
   /* 4. Entry name string (flattened String) */
   /* 5. Entry type code (4 bytes)            */
   /* 6. Entry data length (4 bytes)          */
   /* 7. Entry data (n bytes)                 */

   /* Write entry name length */
   uint32 writeOffset = 0;
   uint8 * buffer = (uint8 *) outBuf;
   {
      uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(f->nameBytes);
      WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
   }

   /* Write entry name */
   memcpy(&buffer[writeOffset], f->name, f->nameBytes); writeOffset += f->nameBytes;

   /* Write entry type code */
   {
      uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(f->typeCode);
      WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
   }

   /* Write entry data length */
   {
      uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(GetMMessageFieldFlattenedSize(f, MFalse));
      WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
   }

   /* Write entry data */
   if (IsTypeCodeVariableSize(f->typeCode))
   {
      uint32 numItems = f->numItems;
      uint32 i; 

      if (f->typeCode == B_MESSAGE_TYPE)
      {
         /* Note that NULL entries will be flattened as empty Messages, since the protocol doesn't support them directly. */
         /* Note also that for this type the number-of-items-in-array field is NOT written into the buffer (sigh)         */
         const MMessage ** msgs = (const MMessage **) f->data;
         for (i=0; i<numItems; i++) 
         {
            const MMessage * subMsg = msgs[i];
            uint32 msgSize = subMsg ? MMGetFlattenedSize(subMsg) : (3*sizeof(uint32));
            uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(msgSize);
            WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
            if (subMsg) 
            {
               MMFlattenMessage(subMsg, &buffer[writeOffset]); writeOffset += msgSize;
            }
            else
            {
               /* No MMessage present?  Then we're going to have to fake one                          */
               /* Format:  0. Protocol revision number (4 bytes, always set to CURRENT_PROTOCOL_VERSION) */
               /*          1. 'what' code (4 bytes)                                                      */
               /*          2. Number of entries (4 bytes)                                                */

               /* Write current protocol version */
               uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(CURRENT_PROTOCOL_VERSION);
               WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));

               /* Write 'what' code (zero) */
               networkByteOrder = B_HOST_TO_LENDIAN_INT32(0);
               WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));

               /* Write number of entries (zero) */
               networkByteOrder = B_HOST_TO_LENDIAN_INT32(0);
               WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
            }
         }
      }
      else
      {
         const MByteBuffer ** bufs = (const MByteBuffer **) f->data;
         int i;

         /* Write the number of items in the array */
         uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(numItems);
         WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));

         for (i=0; i<numItems; i++) 
         {
            uint32 bufSize = bufs[i] ? bufs[i]->numBytes : 0;
            uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(bufSize);
            WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
            memcpy(&buffer[writeOffset], &bufs[i]->bytes, bufSize); writeOffset += bufSize;
         }
      }
   }
   else 
   {
      uint32 dataSize = f->numItems*f->itemSize;
      MBool doMemcpy = MTrue;
      if (BYTE_ORDER != LITTLE_ENDIAN)
      {
         doMemcpy = MFalse;
         switch(f->typeCode)
         {
            case B_BOOL_TYPE: case B_INT8_TYPE: doMemcpy = MTrue;                                   break;
            case B_POINT_TYPE:  SwapCopy(&buffer[writeOffset], f->data, f->numItems*2, sizeof(float)); break;
            case B_RECT_TYPE:   SwapCopy(&buffer[writeOffset], f->data, f->numItems*4, sizeof(float)); break;
            default:            SwapCopy(&buffer[writeOffset], f->data, f->numItems, f->itemSize);     break;
         }
      }
      if (doMemcpy) memcpy(&buffer[writeOffset], f->data, dataSize);
      writeOffset += dataSize;
   }

   return writeOffset;
}
status_t Initialize(int fatbits, const char *device, const char *label, bool noprompt, bool testmode)
{
    if (fatbits != 0 && fatbits != 12 && fatbits != 16 && fatbits != 32) {
        fprintf(stderr,"Error: don't know how to create a %d bit fat\n",fatbits);
        return B_ERROR;
    }
    //XXX the following two checks can be removed when this is fixed:
#ifndef WITH_FLOPPY_SUPPORT
    if (0 != strstr(device,"floppy")) {
        fprintf(stderr,"Error: floppy B_GET_GEOMETRY and B_GET_BIOS_GEOMETRY calls are broken, floppy not supported\n");
        return B_ERROR;
    }
    if (fatbits == 12) {
        fprintf(stderr,"Error: can't create a 12 bit fat on a device other than floppy\n");
        return B_ERROR;
    }
#endif

    printf("device = %s\n",device);

    int fd = open(device, O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "Error: couldn't open file for device %s (%s)\n", device, strerror(errno));
        return B_ERROR;
    }

    bool isRawDevice;
    bool hasBiosGeometry;
    bool hasDeviceGeometry;
    bool hasPartitionInfo;
    device_geometry biosGeometry;
    device_geometry deviceGeometry;
    partition_info 	partitionInfo;

    isRawDevice = 0 != strstr(device, "/raw");
    hasBiosGeometry = B_OK == ioctl(fd, B_GET_BIOS_GEOMETRY, &biosGeometry, sizeof(biosGeometry));
    hasDeviceGeometry = B_OK == ioctl(fd, B_GET_GEOMETRY, &deviceGeometry, sizeof(deviceGeometry));
    hasPartitionInfo = B_OK == ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, sizeof(partitionInfo));

    if (!isRawDevice && !hasBiosGeometry && !hasDeviceGeometry && !hasPartitionInfo)
        isRawDevice = true;

    if (hasBiosGeometry) {
        printf("bios geometry: %ld heads, %ld cylinders, %ld sectors/track, %ld bytes/sector\n",
               biosGeometry.head_count,biosGeometry.cylinder_count,biosGeometry.sectors_per_track,biosGeometry.bytes_per_sector);
    }
    if (hasBiosGeometry) {
        printf("device geometry: %ld heads, %ld cylinders, %ld sectors/track, %ld bytes/sector\n",
               deviceGeometry.head_count,deviceGeometry.cylinder_count,deviceGeometry.sectors_per_track,deviceGeometry.bytes_per_sector);
    }
    if (hasPartitionInfo) {
        printf("partition info: start at %Ld bytes (%Ld sectors), %Ld KB, %Ld MB, %Ld GB\n",
               partitionInfo.offset,
               partitionInfo.offset / 512,
               partitionInfo.offset / 1024,
               partitionInfo.offset / (1024 * 1024),
               partitionInfo.offset / (1024 * 1024 * 1024));
        printf("partition info: size %Ld bytes, %Ld KB, %Ld MB, %Ld GB\n",
               partitionInfo.size,
               partitionInfo.size / 1024,
               partitionInfo.size / (1024 * 1024),
               partitionInfo.size / (1024 * 1024 * 1024));
    }

    if (!isRawDevice && !hasPartitionInfo) {
        fprintf(stderr,"Warning: couldn't get partition information\n");
    }
    if ((hasBiosGeometry && biosGeometry.bytes_per_sector != 512)
            ||	(hasDeviceGeometry && deviceGeometry.bytes_per_sector != 512)) {
        fprintf(stderr,"Error: geometry block size not 512 bytes\n");
        close(fd);
        return B_ERROR;
    } else if (hasPartitionInfo && partitionInfo.logical_block_size != 512) {
        printf("partition logical block size is not 512, it's %ld bytes\n",
               partitionInfo.logical_block_size);
    }

    if (hasDeviceGeometry && deviceGeometry.read_only) {
        fprintf(stderr,"Error: this is a read-only device\n");
        close(fd);
        return B_ERROR;
    }
    if (hasDeviceGeometry && deviceGeometry.write_once) {
        fprintf(stderr,"Error: this is a write-once device\n");
        close(fd);
        return B_ERROR;
    }
    uint64 size = 0;

    if (hasPartitionInfo) {
        size = partitionInfo.size;
    } else if (hasDeviceGeometry) {
        size = uint64(deviceGeometry.bytes_per_sector) * deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count * deviceGeometry.head_count;
    } else if (hasBiosGeometry) {
        size = uint64(biosGeometry.bytes_per_sector) * biosGeometry.sectors_per_track * biosGeometry.cylinder_count * biosGeometry.head_count;
    } else {
        // maybe it's just a file
        struct stat stat;
        if (fstat(fd, &stat) < 0) {
            fprintf(stderr, "Error: couldn't get device partition or geometry information, nor size\n");
            close(fd);
            return B_ERROR;
        }
        size = stat.st_size;
    }

    // TODO still valid on Haiku ?
    /*if (isRawDevice && size > FLOPPY_MAX_SIZE) {
    	fprintf(stderr,"Error: device too large for floppy, or raw devices not supported\n");
    	close(fd);
    	return B_ERROR;
    }*/

    printf("size = %Ld bytes (%Ld sectors), %Ld KB, %Ld MB, %Ld GB\n",
           size,
           size / 512,
           size / 1024,
           size / (1024 * 1024),
           size / (1024 * 1024 * 1024));

    if (fatbits == 0) {
        //auto determine fat type
        if (isRawDevice && size <= FLOPPY_MAX_SIZE && (size / FAT12_CLUSTER_MAX_SIZE) < FAT12_MAX_CLUSTER_COUNT) {
            fatbits = 12;
        } else if ((size / CLUSTER_MAX_SIZE) < FAT16_MAX_CLUSTER_COUNT) {
            fatbits = 16;
        } else if ((size / CLUSTER_MAX_SIZE) < FAT32_MAX_CLUSTER_COUNT) {
            fatbits = 32;
        }
    }

    if (fatbits == 0) {
        fprintf(stderr,"Error: device too large for 32 bit fat\n");
        close(fd);
        return B_ERROR;
    }

    int sectorPerCluster;

    sectorPerCluster = 0;
    if (fatbits == 12) {
        sectorPerCluster = 0;
        if (size <= 4182016LL)
            sectorPerCluster = 2;	// XXX don't know the correct value
        if (size <= 2091008LL)
            sectorPerCluster = 1;	// XXX don't know the correct value
    } else if (fatbits == 16) {
        // special BAD_CLUSTER value is 0xFFF7,
        // but this should work anyway, since space required by
        // two FATs will make maximum cluster count smaller.
        // at least, this is what I think *should* happen
        sectorPerCluster = 0;				//larger than 2 GB must fail
        if (size <= (2048 * 1024 * 1024LL))	// up to 2GB, use 32k clusters
            sectorPerCluster = 64;
        if (size <= (1024 * 1024 * 1024LL))	// up to 1GB, use 16k clusters
            sectorPerCluster = 32;
        if (size <= (512 * 1024 * 1024LL))	// up to 512MB, use 8k clusters
            sectorPerCluster = 16;
        if (size <= (256 * 1024 * 1024LL))	// up to 256MB, use 4k clusters
            sectorPerCluster = 8;
        if (size <= (128 * 1024 * 1024LL))	// up to 128MB, use 2k clusters
            sectorPerCluster = 4;
        if (size <= (16 * 1024 * 1024LL))	// up to 16MB, use 2k clusters
            sectorPerCluster = 2;
        if (size <= 4182016LL)				// smaller than fat32 must fail
            sectorPerCluster = 0;
    }
    if (fatbits == 32) {
        sectorPerCluster = 64;				// default is 32k clusters
        if (size <= (32 * 1024 * 1024 * 1024LL))	// up to 32GB, use 16k clusters
            sectorPerCluster = 32;
        if (size <= (16 * 1024 * 1024 * 1024LL))	// up to 16GB, use 8k clusters
            sectorPerCluster = 16;
        if (size <= (8 * 1024 * 1024 * 1024LL))		// up to 8GB, use 4k clusters
            sectorPerCluster = 8;
        if (size <= (532480 * 512LL))				// up to 260 MB, use 0.5k clusters
            sectorPerCluster = 1;
        if (size <= (66600 * 512LL))		// smaller than 32.5 MB must fail
            sectorPerCluster = 0;
    }

    if (sectorPerCluster == 0) {
        fprintf(stderr,"Error: failed to determine sector per cluster value, partition too large for %d bit fat\n",fatbits);
        close(fd);
        return B_ERROR;
    }

    int reservedSectorCount = 0; // avoid compiler warning
    int rootEntryCount = 0; // avoid compiler warning
    int numFATs;
    int sectorSize;
    uint8 biosDriveId;

    // get bios drive-id, or use 0x80
    if (B_OK != ioctl(fd, B_GET_BIOS_DRIVE_ID, &biosDriveId, sizeof(biosDriveId))) {
        biosDriveId = 0x80;
    } else {
        printf("bios drive id: 0x%02x\n", (int)biosDriveId);
    }

    // default parameters for the bootsector
    numFATs = 2;
    sectorSize = 512;
    if (fatbits == 12 || fatbits == 16)
        reservedSectorCount = 1;
    if (fatbits == 32)
        reservedSectorCount = 32;
    if (fatbits == 12)
        rootEntryCount = 128; // XXX don't know the correct value
    if (fatbits == 16)
        rootEntryCount = 512;
    if (fatbits == 32)
        rootEntryCount = 0;

    // Determine FATSize
    // calculation done as MS recommends
    uint64 dskSize = size / sectorSize;
    uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1)) / sectorSize;
    uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors);
    uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs;
    if (fatbits == 32)
        tmpVal2 = tmpVal2 / 2;
    uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2;
    // FATSize should now contain the size of *one* FAT, measured in sectors
    // RootDirSectors should now contain the size of the fat12/16 root directory, measured in sectors

    printf("fatbits = %d, clustersize = %d\n", fatbits, sectorPerCluster * 512);
    printf("FAT size is %ld sectors\n", FATSize);
    printf("disk label: %s\n", label);

    char bootsector[512];
    memset(bootsector,0x00,512);
    memcpy(bootsector + BOOTJMP_START_OFFSET, bootjmp, sizeof(bootjmp));
    memcpy(bootsector + BOOTCODE_START_OFFSET, bootcode, sizeof(bootcode));

    if (fatbits == 32) {
        bootsector32 *bs = (bootsector32 *)bootsector;
        uint16 temp16;
        uint32 temp32;
        memcpy(bs->BS_OEMName,"Haiku   ",8);
        bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
        bs->BPB_SecPerClus = sectorPerCluster;
        bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
        bs->BPB_NumFATs = numFATs;
        bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
        bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(0);
        bs->BPB_Media = 0xF8;
        bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(0);
        temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
        bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
        temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
        bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
        temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
        bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
        temp32 = size / 512;
        bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32);
        bs->BPB_FATSz32 = B_HOST_TO_LENDIAN_INT32(FATSize);
        bs->BPB_ExtFlags = B_HOST_TO_LENDIAN_INT16(0);
        bs->BPB_FSVer = B_HOST_TO_LENDIAN_INT16(0);
        bs->BPB_RootClus = B_HOST_TO_LENDIAN_INT32(FAT32_ROOT_CLUSTER);
        bs->BPB_FSInfo = B_HOST_TO_LENDIAN_INT16(FSINFO_SECTOR_NUM);
        bs->BPB_BkBootSec = B_HOST_TO_LENDIAN_INT16(BACKUP_SECTOR_NUM);
        memset(bs->BPB_Reserved,0,12);
        bs->BS_DrvNum = biosDriveId;
        bs->BS_Reserved1 = 0x00;
        bs->BS_BootSig = 0x29;
        *(uint32*)bs->BS_VolID = (uint32)system_time();
        memcpy(bs->BS_VolLab,"NO NAME    ",11);
        memcpy(bs->BS_FilSysType,"FAT32   ",8);
        bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
    } else {
        bootsector1216 *bs = (bootsector1216 *)bootsector;
        uint16 temp16;
        uint32 temp32;
        uint32 sectorcount = size / 512;
        memcpy(bs->BS_OEMName, "Haiku   ", 8);
        bs->BPB_BytsPerSec = B_HOST_TO_LENDIAN_INT16(sectorSize);
        bs->BPB_SecPerClus = sectorPerCluster;
        bs->BPB_RsvdSecCnt = B_HOST_TO_LENDIAN_INT16(reservedSectorCount);
        bs->BPB_NumFATs = numFATs;
        bs->BPB_RootEntCnt = B_HOST_TO_LENDIAN_INT16(rootEntryCount);
        temp16 = (sectorcount <= 65535) ? sectorcount : 0;
        bs->BPB_TotSec16 = B_HOST_TO_LENDIAN_INT16(temp16);
        bs->BPB_Media = 0xF8;
        bs->BPB_FATSz16 = B_HOST_TO_LENDIAN_INT16(FATSize);
        temp16 = hasBiosGeometry ? biosGeometry.sectors_per_track : 63;
        bs->BPB_SecPerTrk = B_HOST_TO_LENDIAN_INT16(temp16);
        temp16 = hasBiosGeometry ? biosGeometry.head_count : 255;
        bs->BPB_NumHeads = B_HOST_TO_LENDIAN_INT16(temp16);
        temp32 = hasPartitionInfo ? (partitionInfo.size / 512) : 0;
        bs->BPB_HiddSec = B_HOST_TO_LENDIAN_INT32(temp32);
        temp32 = (sectorcount <= 65535) ? 0 : sectorcount;
        bs->BPB_TotSec32 = B_HOST_TO_LENDIAN_INT32(temp32);
        bs->BS_DrvNum = biosDriveId;
        bs->BS_Reserved1 = 0x00;
        bs->BS_BootSig = 0x29;
        *(uint32*)bs->BS_VolID = (uint32)system_time();
        memcpy(bs->BS_VolLab,"NO NAME    ",11);
        memcpy(bs->BS_FilSysType,(fatbits == 12) ? "FAT12   " : "FAT16   ",8);
        bs->signature = B_HOST_TO_LENDIAN_INT16(0xAA55);
    }

    if (!noprompt) {
        printf("\n");
        printf("Initializing will erase all existing data on the drive.\n");
        printf("Do you wish to proceed? ");
        char answer[1000];
        char *p;
        memset(answer, 0, 1000);
        fflush(stdout);
        p = fgets(answer, 1000, stdin);
        if (p && (p=strchr(p, '\n')))
            *p = '\0'; /* remove newline */
        if ((p == NULL) || (strlen(answer) < 1) || (0 != strncasecmp(answer, "yes", strlen(answer)))) {
            printf("drive NOT initialized\n");
            close(fd);
            return B_OK;
        }
    }
    if (testmode) {
        close(fd);
        return B_OK;
    }

    // Disk layout:
    // 0) reserved sectors, this includes the bootsector, fsinfosector and bootsector backup
    // 1) FAT
    // 2) root directory (not on fat32)
    // 3) file & directory data

    ssize_t written;

    // initialize everything with zero first
    // avoid doing 512 byte writes here, they are slow
    printf("Writing FAT\n");
    char * zerobuffer = (char *)malloc(65536);
    memset(zerobuffer,0,65536);
    int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize) + rootDirSectors);
    int64 pos = 0;
    while (bytes_to_write > 0) {
        ssize_t writesize = min_c(bytes_to_write, 65536);
        written = write_pos(fd, pos, zerobuffer, writesize);
        if (written != writesize) {
            fprintf(stderr,"Error: write error near sector %Ld\n",pos / 512);
            close(fd);
            return B_ERROR;
        }
        bytes_to_write -= writesize;
        pos += writesize;
    }
    free(zerobuffer);

    //write boot sector
    printf("Writing boot block\n");
    written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512);
    if (written != 512) {
        fprintf(stderr,"Error: write error at sector %d\n", BOOT_SECTOR_NUM);
        close(fd);
        return B_ERROR;
    }

    if (fatbits == 32) {
        written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512);
        if (written != 512) {
            fprintf(stderr,"Error: write error at sector %d\n", BACKUP_SECTOR_NUM);
            close(fd);
            return B_ERROR;
        }
    }

    //write first fat sector
    printf("Writing first FAT sector\n");
    uint8 sec[512];
    memset(sec,0,512);
    if (fatbits == 12) {
        //FAT[0] contains media byte in lower 8 bits, all other bits set to 1
        //FAT[1] contains EOF marker
        sec[0] = 0xF8;
        sec[1] = 0xFF;
        sec[2] = 0xFF;
    } else if (fatbits == 16) {
        //FAT[0] contains media byte in lower 8 bits, all other bits set to 1
        sec[0] = 0xF8;
        sec[1] = 0xFF;
        //FAT[1] contains EOF marker
        sec[2] = 0xFF;
        sec[3] = 0xFF;
    } else if (fatbits == 32) {
        //FAT[0] contains media byte in lower 8 bits, all other bits set to 1
        sec[0] = 0xF8;
        sec[1] = 0xFF;
        sec[2] = 0xFF;
        sec[3] = 0xFF;
        //FAT[1] contains EOF marker
        sec[4] = 0xFF;
        sec[5] = 0xFF;
        sec[6] = 0xFF;
        sec[7] = 0x0F;
        //FAT[2] contains EOF marker, used to terminate root directory
        sec[8] = 0xFF;
        sec[9] = 0xFF;
        sec[10] = 0xFF;
        sec[11] = 0x0F;
    }
    written = write_pos(fd, reservedSectorCount * 512, sec, 512);
    if (written != 512) {
        fprintf(stderr,"Error: write error at sector %d\n", reservedSectorCount);
        close(fd);
        return B_ERROR;
    }
    if (numFATs > 1) {
        written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512);
        if (written != 512) {
            fprintf(stderr,"Error: write error at sector %ld\n", reservedSectorCount + FATSize);
            close(fd);
            return B_ERROR;
        }
    }

    //write fsinfo sector
    if (fatbits == 32) {
        printf("Writing boot info\n");
        //calculate total sector count first
        uint64 free_count = size / 512;
        //now account for already by metadata used sectors
        free_count -= reservedSectorCount + (numFATs * FATSize) + rootDirSectors;
        //convert from sector to clustercount
        free_count /= sectorPerCluster;
        //and account for 1 already used cluster of root directory
        free_count -= 1;
        fsinfosector32 fsinfosector;
        memset(&fsinfosector,0x00,512);
        fsinfosector.FSI_LeadSig 	= B_HOST_TO_LENDIAN_INT32(0x41615252);
        fsinfosector.FSI_StrucSig 	= B_HOST_TO_LENDIAN_INT32(0x61417272);
        fsinfosector.FSI_Free_Count = B_HOST_TO_LENDIAN_INT32((uint32)free_count);
        fsinfosector.FSI_Nxt_Free 	= B_HOST_TO_LENDIAN_INT32(3);
        fsinfosector.FSI_TrailSig 	= B_HOST_TO_LENDIAN_INT32(0xAA550000);
        written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512);
        if (written != 512) {
            fprintf(stderr,"Error: write error at sector %d\n", FSINFO_SECTOR_NUM);
            close(fd);
            return B_ERROR;
        }
    }

    //write volume label into root directory
    printf("Writing root directory\n");
    if (fatbits == 12 || fatbits == 16) {
        uint8 data[512];
        memset(data, 0, 512);
        CreateVolumeLabel(data, label);
        uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
        written = write_pos(fd, rootDirSector * 512, data, 512);
        if (written != 512) {
            fprintf(stderr,"Error: write error at sector %ld\n", rootDirSector);
            close(fd);
            return B_ERROR;
        }
    } else if (fatbits == 32) {
        int size = 512 * sectorPerCluster;
        uint8 *cluster = (uint8*)malloc(size);
        memset(cluster, 0, size);
        CreateVolumeLabel(cluster, label);
        uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize) + rootDirSectors;
        written = write_pos(fd, rootDirSector * 512, cluster, size);
        free(cluster);
        if (written != size) {
            fprintf(stderr,"Error: write error at sector %ld\n", rootDirSector);
            close(fd);
            return B_ERROR;
        }
    }

    ioctl(fd, B_FLUSH_DRIVE_CACHE);
    close(fd);

    return B_OK;
}
Example #17
0
// main
int
main(int argc, const char *const *argv)
{
	kArgc = argc;
	kArgv = argv;

	if (argc < 2)
		print_usage_and_exit(true);

	// parameters
	const char **files = new const char*[argc];
	int fileCount = 0;
	bool dryRun = false;
	off_t startOffset = 0;

	// parse arguments
	for (int argi = 1; argi < argc;) {
		const char *arg = argv[argi++];

		if (arg[0] == '-') {
			if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
				print_usage_and_exit(false);
			} else if (strcmp(arg, "--dry-run") == 0) {
				dryRun = true;
			} else if (strcmp(arg, "-alert") == 0) {
				// ignore
			} else if (strcmp(arg, "-full") == 0) {
				// ignore
			} else if (strcmp(arg, "--start-offset") == 0) {
				if (argi >= argc)
					print_usage_and_exit(true);
				startOffset = strtoll(argv[argi++], NULL, 0);
			} else if (strcmp(arg, "-safe") == 0) {
				fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n");
				exit(1);
			} else {
				print_usage_and_exit(true);
			}

		} else {
			files[fileCount++] = arg;
		}
	}

	// we need at least one file
	if (fileCount == 0)
		print_usage_and_exit(true);

	// read the boot code
	uint8 *bootCodeData = NULL;
#ifndef __ANTARES__
	bootCodeData = read_boot_code_data(argv[0]);
#else
	image_info info;
	if (find_own_image(&info) == B_OK)
		bootCodeData = read_boot_code_data(info.name);
#endif
	if (!bootCodeData) {
		fprintf(stderr, "Error: Failed to read \n");
		exit(1);
	}

	// iterate through the files and make them bootable
	status_t error;
	for (int i = 0; i < fileCount; i++) {
		const char *fileName = files[i];
		BEntry entry;
		error = entry.SetTo(fileName, true);
		if (error != B_OK) {
			fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
				fileName, strerror(error));
			exit(1);
		}

		// get stat to check the type of the file
		struct stat st;
		error = entry.GetStat(&st);
		if (error != B_OK) {
			fprintf(stderr, "Error: Failed to stat \"%s\": %s\n",
				fileName, strerror(error));
			exit(1);
		}

		bool noPartition = false;
		int64 partitionOffset = 0;
		fs_info info;	// needs to be here (we use the device name later)
		if (S_ISDIR(st.st_mode)) {
			#if defined(__BEOS__) || defined(__ANTARES__)

				// a directory: get the device
				error = fs_stat_dev(st.st_dev, &info);
				if (error != B_OK) {
					fprintf(stderr, "Error: Failed to determine device for "
						"\"%s\": %s\n", fileName, strerror(error));
					exit(1);
				}

				fileName = info.device_name;

			#else

				(void)info;
				fprintf(stderr, "Error: Specifying directories not supported "
					"on this platform!\n");
				exit(1);

			#endif

		} else if (S_ISREG(st.st_mode)) {
			// a regular file: fine
			noPartition = true;
		} else if (S_ISCHR(st.st_mode)) {
			// character special: a device or partition under BeOS
			// or under FreeBSD
			#if !(defined(__BEOS__) || defined(__ANTARES__)) && !defined(ANTARES_HOST_PLATFORM_FREEBSD)

				fprintf(stderr, "Error: Character special devices not "
					"supported on this platform.\n");
				exit(1);

			#endif

			#ifdef ANTARES_HOST_PLATFORM_FREEBSD

				// chop off the trailing number
				int fileNameLen = strlen(fileName);
				int baseNameLen = -1;
				for (int k = fileNameLen - 1; k >= 0; k--) {
					if (!isdigit(fileName[k])) {
						baseNameLen = k + 1;
						break;
					}
				}

				// Remove de 's' from 'ad2s2' slice device (partition for DOS
				// users) to get 'ad2' base device
				baseNameLen--;

				if (baseNameLen < 0) {
					// only digits?
					fprintf(stderr, "Error: Failed to get base device name.\n");
					exit(1);
				}

				if (baseNameLen < fileNameLen) {
					// get base device name and partition index
					char baseDeviceName[B_PATH_NAME_LENGTH];
					int partitionIndex = atoi(fileName + baseNameLen + 1);
						// Don't forget the 's' of slice :)
					memcpy(baseDeviceName, fileName, baseNameLen);
					baseDeviceName[baseNameLen] = '\0';

					// open base device
					int baseFD = open(baseDeviceName, O_RDONLY);
					if (baseFD < 0) {
						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
							baseDeviceName, strerror(errno));
						exit(1);
					}

					// get device size
					int64 deviceSize;
					if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) {
						fprintf(stderr, "Error: Failed to get device geometry "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
						exit(1);
					}

					// parse the partition map
					// TODO: block size!
					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
					PartitionMap map;
					error = parser.Parse(NULL, &map);
					if (error != B_OK) {
						fprintf(stderr, "Error: Parsing partition table on "
							"device \"%s\" failed: %s\n", baseDeviceName,
							strerror(error));
						exit(1);
					}

					close(baseFD);

					// check the partition we are supposed to write at
					Partition *partition = map.PartitionAt(partitionIndex - 1);
					if (!partition || partition->IsEmpty()) {
						fprintf(stderr, "Error: Invalid partition index %d.\n",
							partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					if (partition->IsExtended()) {
						fprintf(stderr, "Error: Partition %d is an extended "
							"partition.\n", partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					partitionOffset = partition->Offset();

				} else {
					// The given device is the base device. We'll write at
					// offset 0.
				}

			#endif // ANTARES_HOST_PLATFORM_FREEBSD

		} else if (S_ISBLK(st.st_mode)) {
			// block device: a device or partition under Linux or Darwin
			#ifdef ANTARES_HOST_PLATFORM_LINUX

				// chop off the trailing number
				int fileNameLen = strlen(fileName);
				int baseNameLen = -1;
				for (int k = fileNameLen - 1; k >= 0; k--) {
					if (!isdigit(fileName[k])) {
						baseNameLen = k + 1;
						break;
					}
				}

				if (baseNameLen < 0) {
					// only digits?
					fprintf(stderr, "Error: Failed to get base device name.\n");
					exit(1);
				}

				if (baseNameLen < fileNameLen) {
					// get base device name and partition index
					char baseDeviceName[B_PATH_NAME_LENGTH];
					int partitionIndex = atoi(fileName + baseNameLen);
					memcpy(baseDeviceName, fileName, baseNameLen);
					baseDeviceName[baseNameLen] = '\0';

					// open base device
					int baseFD = open(baseDeviceName, O_RDONLY);
					if (baseFD < 0) {
						fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
							baseDeviceName, strerror(errno));
						exit(1);
					}

					// get device size -- try BLKGETSIZE64, but, if it doesn't
					// work, fall back to the obsolete HDIO_GETGEO
					int64 deviceSize;
					hd_geometry geometry;
					if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0
						&& deviceSize > 0) {
						// looks good
					} else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) {
						deviceSize = (int64)geometry.heads * geometry.sectors
							* geometry.cylinders * 512;
					} else {
						fprintf(stderr, "Error: Failed to get device geometry "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
						exit(1);
					}

					// parse the partition map
					// TODO: block size!
					PartitionMapParser parser(baseFD, 0, deviceSize, 512);
					PartitionMap map;
					error = parser.Parse(NULL, &map);
					if (error != B_OK) {
						fprintf(stderr, "Error: Parsing partition table on "
							"device \"%s\" failed: %s\n", baseDeviceName,
							strerror(error));
						exit(1);
					}

					close(baseFD);

					// check the partition we are supposed to write at
					Partition *partition = map.PartitionAt(partitionIndex - 1);
					if (!partition || partition->IsEmpty()) {
						fprintf(stderr, "Error: Invalid partition index %d.\n",
							partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					if (partition->IsExtended()) {
						fprintf(stderr, "Error: Partition %d is an extended "
							"partition.\n", partitionIndex);
						dump_partition_map(map);
						exit(1);
					}

					partitionOffset = partition->Offset();
				} else {
					// The given device is the base device. We'll write at
					// offset 0.
				}

			#elif defined(ANTARES_HOST_PLATFORM_DARWIN)
				// chop off the trailing number
				int fileNameLen = strlen(fileName);
				int baseNameLen = fileNameLen - 2;

				// get base device name and partition index
				char baseDeviceName[B_PATH_NAME_LENGTH];
				int partitionIndex = atoi(fileName + baseNameLen + 1);
				memcpy(baseDeviceName, fileName, baseNameLen);
				baseDeviceName[baseNameLen] = '\0';

				// open base device
				int baseFD = open(baseDeviceName, O_RDONLY);
				if (baseFD < 0) {
					fprintf(stderr, "Error: Failed to open \"%s\": %s\n",
							baseDeviceName, strerror(errno));
					exit(1);
				}

				// get device size
				int64 blockSize;
				int64 blockCount;
				int64 deviceSize;
				if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) {
					fprintf(stderr, "Error: Failed to get block size "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
					exit(1);
				}
				if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) {
					fprintf(stderr, "Error: Failed to get block count "
							"for \"%s\": %s\n", baseDeviceName,
							strerror(errno));
					exit(1);
				}

				deviceSize = blockSize * blockCount;

				// parse the partition map
				PartitionMapParser parser(baseFD, 0, deviceSize, blockSize);
				PartitionMap map;
				error = parser.Parse(NULL, &map);
				if (error != B_OK) {
					fprintf(stderr, "Error: Parsing partition table on "
							"device \"%s\" failed: %s\n", baseDeviceName,
							strerror(error));
					exit(1);
				}

				close(baseFD);

				// check the partition we are supposed to write at
				Partition *partition = map.PartitionAt(partitionIndex - 1);
				if (!partition || partition->IsEmpty()) {
					fprintf(stderr, "Error: Invalid partition index %d.\n",
						partitionIndex);
					dump_partition_map(map);
					exit(1);
				}

				if (partition->IsExtended()) {
					fprintf(stderr, "Error: Partition %d is an extended "
						"partition.\n", partitionIndex);
					dump_partition_map(map);
					exit(1);
				}
				partitionOffset = partition->Offset();
			#else
			// partitions are block devices under Antares, but not under BeOS
			#ifndef __ANTARES__
				fprintf(stderr, "Error: Block devices not supported on this "
					"platform!\n");
				exit(1);
			#endif	// __ANTARES__

			#endif
		} else {
			fprintf(stderr, "Error: File type of \"%s\" is not supported.\n",
				fileName);
			exit(1);
		}

		// open the file
		int fd = open(fileName, O_RDWR);
		if (fd < 0) {
			fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName,
				strerror(errno));
			exit(1);
		}

		#if (defined(__BEOS__) || defined(__ANTARES__))

			// get a partition info
			if (!noPartition
				&& strlen(fileName) >= 3
				&& strncmp("raw", fileName + strlen(fileName) - 3, 3)) {
				partition_info partitionInfo;
				if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo,
						sizeof(partitionInfo)) == 0) {
					partitionOffset = partitionInfo.offset;
				} else {
					fprintf(stderr, "Error: Failed to get partition info: %s\n",
						strerror(errno));
					exit(1);
				}
			}

		#endif	// __BEOS__

		// adjust the partition offset in the boot code data
		// hard coded sector size: 512 bytes
		*(uint32*)(bootCodeData + kPartitionOffsetOffset)
			= B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512));

		// write the boot code
		printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64
			" bytes, start offset = %" B_PRIdOFF ") "
			"...\n", fileName, partitionOffset, startOffset);

		write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0,
			kFirstBootCodePartSize, dryRun);
		write_boot_code_part(fileName, fd, startOffset, bootCodeData,
			kSecondBootCodePartOffset, kSecondBootCodePartSize,
			dryRun);

#ifdef __ANTARES__
		// check if this partition is mounted
		BDiskDeviceRoster roster;
		BPartition* partition;
		BDiskDevice device;
		status_t status = roster.GetPartitionForPath(fileName, &device,
			&partition);
		if (status != B_OK) {
			status = roster.GetFileDeviceForPath(fileName, &device);
			if (status == B_OK)
				partition = &device;
		}
		if (status == B_OK && partition->IsMounted() && !dryRun) {
			// This partition is mounted, we need to tell BFS to update its
			// boot block (we are using part of the same logical block).
			BPath path;
			status = partition->GetMountPoint(&path);
			if (status == B_OK) {
				update_boot_block update;
				update.offset = kSecondBootCodePartOffset - 512;
				update.data = bootCodeData + kSecondBootCodePartOffset;
				update.length = kSecondBootCodePartSize;

				int mountFD = open(path.Path(), O_RDONLY);
				if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update,
						sizeof(update_boot_block)) != 0) {
					fprintf(stderr, "Could not update BFS boot block: %s\n",
						strerror(errno));
				}
				close(mountFD);
			} else {
				fprintf(stderr, "Could not update BFS boot code while the "
					"partition is mounted!\n");
			}
		}
#endif	// __ANTARES__

		close(fd);
	}

	return 0;
}