#!/usr/local/bin/ruby -w
#
# vim:sw=2 ts=8:et sta:fdm=marker
#
#
# Copyright (c) 2005 Ariff Abdullah
#        (skywizard@MyBSD.org.my) All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#        $Id$
#
# Date: Sun Nov 27 08:14:29 MYT 2005
#   OS: FreeBSD osaka.MyBSD.org.my 6.0-RELEASE i386
#

module IOCCOM
  PARM_MASK = 0x1fff
  VOID      = 0x20000000
  OUT       = 0x40000000
  IN        = 0x80000000
  INOUT     = IN|OUT
  DIRMASK   = 0xe0000000
  def PARM_LEN(x)
    (x >> 16) & PARM_MASK
  end
  def BASECMD(x)
    x & ~(PARM_MASK << 16)
  end
  def GROUP(x)
    (x >> 8) & 0xff
  end
  def _IOC(inout, group, num, len)
    inout | ((len & PARM_MASK) << 16) | ((group.is_a?(String) ? group[0] : group) << 8) | num
  end
  def _IO(g, n)
    _IOC(VOID, g, n, 0)
  end
  def _IOR(g, n, t)
    _IOC(OUT, g, n, t)
  end
  def _IOW(g, n, t)
    _IOC(IN, g, n, t)
  end
  def _IOWR(g, n, t)
    _IOC(INOUT, g, n, t)
  end
  module_function :PARM_LEN, :BASECMD, :GROUP
  module_function :_IOC, :_IO, :_IOR, :_IOW, :_IOWR
end

module DISK
  class << self
    include IOCCOM
  end
  DIOCGMEDIASIZE = _IOR('d', 129, 8)
end

module CDIO
  class << self
    include IOCCOM
  end
  CDIOCSTART = _IO('c', 22)
  CDIOCEJECT = _IO('c', 24)
  CDIOCCLOSE = _IO('c', 28)
  sizeof_ioc_toc_header = [0, 0, 0].pack('SC2').size()
  CDIOREADTOCHEADER = _IOR('c', 4, sizeof_ioc_toc_header)
  # XXX struct with bitfield black magic art
  sizeof_cd_toc_entry = [0, 0, 0].pack('xC2xN').size()
  sizeof_ioc_read_toc_single_entry = [0, 0].pack('C2x2').size() +
      sizeof_cd_toc_entry
  CDIOREADTOCENTRY = _IOWR('c', 6, sizeof_ioc_read_toc_single_entry)
  sizeof_ioc_read_toc_entry = [0, 0, 0, "\0"].pack('C2SP').size()
  CDIOREADTOCENTRYS = _IOWR('c', 5, sizeof_ioc_read_toc_entry)

  CD_LBA_FORMAT = 1
end

module CDRIO
  class << self
    include IOCCOM
  end
  CDR_DB_RAW          = 0x0
  CDR_DB_RAW_PQ       = 0x1
  CDR_DB_RAW_PW       = 0x2
  CDR_DB_RAW_PW_R     = 0x3
  CDR_DB_RES_4        = 0x4
  CDR_DB_RES_5        = 0x5
  CDR_DB_RES_6        = 0x6
  CDR_DB_VS_7         = 0x7
  CDR_DB_ROM_MODE1    = 0x8
  CDR_DB_ROM_MODE2    = 0x9
  CDR_DB_XA_MODE1     = 0xa
  CDR_DB_XA_MODE2_F1  = 0xb
  CDR_DB_XA_MODE2_F2  = 0xc
  CDR_DB_XA_MODE2_MIX = 0xd
  CDR_DB_RES_14       = 0xe
  CDR_DB_VS_15        = 0xf
  
  CDR_SESS_CDROM    = 0x00
  CDR_SESS_CDI      = 0x10
  CDR_SESS_CDROM_XA = 0x20
  CDR_SESS_NONE     = 0x00
  CDR_SESS_FINAL    = 0x01
  CDR_SESS_RESERVED = 0x02
  CDR_SESS_MULTI    = 0x03

  sizeof_int = [0].pack('i').size()
  sizeof_cdr_track = [0, 0, 0].pack('i3').size()
  sizeof_cdr_cuesheet = [0, "\0", 0, 0, 0].pack('iPi3').size()
  CDRIOCBLANK   = _IOW('c', 100, sizeof_int)
  CDR_B_ALL     = 0x0
  CDR_B_MIN     = 0x1
  CDR_B_SESSION = 0x6

  CDIOCRESET              = _IO('c', 21)
  CDRIOCNEXTWRITEABLEADDR = _IOR('c', 101, sizeof_int)
  CDRIOCINITWRITER        = _IOW('c', 102, sizeof_int)
  CDRIOCINITTRACK         = _IOW('c', 103, sizeof_cdr_track)
  CDRIOCSENDCUE           = _IOW('c', 104, sizeof_cdr_cuesheet)
  CDRIOCFLUSH             = _IO('c', 105)
  CDRIOCFIXATE            = _IOW('c', 106, sizeof_int)
  CDRIOCREADSPEED         = _IOW('c', 107, sizeof_int)
  CDRIOCWRITESPEED        = _IOW('c', 108, sizeof_int)
  CDRIOCGETBLOCKSIZE      = _IOR('c', 109, sizeof_int)
  CDRIOCSETBLOCKSIZE      = _IOW('c', 110, sizeof_int)
  CDRIOCGETPROGRESS       = _IOR('c', 111, sizeof_int)

  CDR_MAX_SPEED = 0xffff
end

dev = ENV['CDROM'] || '/dev/acd0'
blksz = 2048
case ARGV.size()
  when 1
    blksz = ARGV[0].to_i
  when 2
    blksz = ARGV[0].to_i
    dev = ARGV[1]
else
  raise ArgumentError, "Usage: #{File.basename($0)} <blocksize> <cdrom device>"
end

if blksz < 2048 || blksz > 2352
  raise ArgumentError, "Invalid blocksize - #{blksz}"
end

unless File.chardev?(dev)
  raise ArgumentError, "Invalid character device - #{dev}"
end

fd = File.open(dev, 'r')
fd.ioctl(CDRIO::CDRIOCSETBLOCKSIZE, [blksz].pack('i'))

blksz = [0].pack('i')
fd.ioctl(CDRIO::CDRIOCGETBLOCKSIZE, blksz)
puts blksz.unpack('i')[0]
