Blame lib/driver/FreeBSD/freebsd_ioctl.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003, 2004, 2005, 2008, 2013, 2016
Packit dd8086
  Rocky Bernstein <rocky@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
Packit dd8086
/* This file contains FreeBSD-specific code and implements low-level
Packit dd8086
   control of the CD drive. Culled initially I think from xine's or
Packit dd8086
   mplayer's FreeBSD code with lots of modifications.
Packit dd8086
*/
Packit dd8086

Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
# include "config.h"
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_FREEBSD_CDROM
Packit dd8086
Packit dd8086
#include "freebsd.h"
Packit dd8086
Packit dd8086
/* Check a drive to see if it is a CD-ROM
Packit dd8086
   Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive
Packit dd8086
   and -1 if no device exists .
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
cdio_is_cdrom_freebsd_ioctl(char *drive, char *mnttype)
Packit dd8086
{
Packit dd8086
  bool is_cd=false;
Packit dd8086
  int cdfd;
Packit dd8086
  struct ioc_toc_header    tochdr;
Packit dd8086
Packit dd8086
  /* If it doesn't exist, return -1 */
Packit dd8086
  if ( !cdio_is_device_quiet_generic(drive) ) {
Packit dd8086
    return(false);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* ts 13 Jan 2009
Packit dd8086
     The ioctl below seems to be of little significance if one does not insist
Packit dd8086
     in readable media.
Packit dd8086
     Various of its failures are not caused by not being a CD drive
Packit dd8086
     but by unreadable media situations. A burn program must handle these
Packit dd8086
     situations rather than refusing to see the drive.
Packit dd8086
   */
Packit dd8086
 return(true);
Packit dd8086
Packit dd8086
#ifndef Libcdio_on_freeBSD_unsuitable_code
Packit dd8086
Packit dd8086
  /* If it does exist, verify that it's an available CD-ROM */
Packit dd8086
  cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
Packit dd8086
Packit dd8086
  /* Should we want to test the condition in more detail:
Packit dd8086
     ENOENT is the error for /dev/xxxxx does not exist;
Packit dd8086
     ENODEV means there's no drive present. */
Packit dd8086
Packit dd8086
  if ( cdfd >= 0 ) {
Packit dd8086
    int ret;
Packit dd8086
Packit dd8086
   ret = ioctl(cdfd, CDIOREADTOCHEADER, &tochdr);
Packit dd8086
Packit dd8086
/*
Packit dd8086
  fprintf(stderr, "libcdio_DEBUG: ioctl(\"%s\", (O_RDONLY|O_EXCL|O_NONBLOCK) = %d (errno= %d)\n", drive, ret, errno);
Packit dd8086
*/
Packit dd8086
Packit dd8086
    if ( ret != -1 ) {
Packit dd8086
      is_cd = true;
Packit dd8086
    } else if ( errno == ENXIO ) { /* Device not configured */
Packit dd8086
      /* ts 9 Jan 2010 , FreeBSD 8.0
Packit dd8086
         This error is issued with CAM device cd0 if no media is loaded.
Packit dd8086
      */
Packit dd8086
      is_cd = true;
Packit dd8086
    } else if ( errno == EIO ) { /* I/O error */
Packit dd8086
      /* ts 9 Jan 2010 , FreeBSD 8.0
Packit dd8086
         This error is issued with ATAPI device acd0 if no media is loaded.
Packit dd8086
      */
Packit dd8086
      is_cd = true;
Packit dd8086
    } else if ( errno == EINVAL ) { /* Invalid argument */
Packit dd8086
      /* ts 13 Jan 2010 , FreeBSD 8.0
Packit dd8086
         This error is issued with USB device cd1 if a blank CD-RW is loaded.
Packit dd8086
      */
Packit dd8086
      is_cd = true;
Packit dd8086
    }
Packit dd8086
    close(cdfd);
Packit dd8086
  } else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) {
Packit dd8086
    /* Even if we can't read it, it might be mounted */
Packit dd8086
    is_cd = true;
Packit dd8086
  }
Packit dd8086
  return(is_cd);
Packit dd8086
Packit dd8086
#endif /* Libcdio_on_freeBSD_unsuitable_codE */
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads a single mode2 sector from cd device into data starting from lsn.
Packit dd8086
   Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
int
Packit dd8086
read_audio_sectors_freebsd_ioctl (_img_private_t *_obj, void *data, lsn_t lsn,
Packit dd8086
				  unsigned int nblocks)
Packit dd8086
{
Packit dd8086
  int bsize = CDIO_CD_FRAMESIZE_RAW;
Packit dd8086
Packit dd8086
  /* set block size */
Packit dd8086
  if (ioctl(_obj->gen.fd, CDRIOCSETBLOCKSIZE, &bsize) == -1) return 1;
Packit dd8086
Packit dd8086
  /* read a frame */
Packit dd8086
  if (pread(_obj->gen.fd, data, nblocks*bsize, lsn*bsize) != nblocks*bsize) {
Packit dd8086
    perror("read_audio_sectors_freebsd_ioctl");
Packit dd8086
    return 1;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads a single mode2 sector from cd device into data starting
Packit dd8086
   from lsn. Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
int
Packit dd8086
read_mode2_sector_freebsd_ioctl (_img_private_t *p_env, void *data, lsn_t lsn,
Packit dd8086
				 bool b_form2)
Packit dd8086
{
Packit dd8086
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
Packit dd8086
  int retval;
Packit dd8086
Packit dd8086
  if ( !b_form2 )
Packit dd8086
    return cdio_generic_read_form1_sector (p_env, buf, lsn);
Packit dd8086
Packit dd8086
  if ( (retval = read_audio_sectors_freebsd_ioctl (p_env, buf, lsn, 1)) )
Packit dd8086
    return retval;
Packit dd8086
Packit dd8086
  memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, M2RAW_SECTOR_SIZE);
Packit dd8086
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return the size of the CD in logical block address (LBA) units.
Packit dd8086
 */
Packit dd8086
lsn_t
Packit dd8086
get_disc_last_lsn_freebsd_ioctl (_img_private_t *p_obj)
Packit dd8086
{
Packit dd8086
  struct ioc_read_toc_single_entry tocent;
Packit dd8086
  uint32_t size;
Packit dd8086
Packit dd8086
  tocent.track = CDIO_CDROM_LEADOUT_TRACK;
Packit dd8086
  tocent.address_format = CDIO_CDROM_LBA;
Packit dd8086
  if (ioctl (p_obj->gen.fd, CDIOREADTOCENTRY, &tocent) == -1)
Packit dd8086
    {
Packit dd8086
      perror ("ioctl(CDROMREADTOCENTRY)");
Packit dd8086
      exit (EXIT_FAILURE);
Packit dd8086
    }
Packit dd8086
Packit dd8086
  size = tocent.entry.addr.lba;
Packit dd8086
Packit dd8086
  return size;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
Packit dd8086
  DRIVER_OP_ERROR on error.
Packit dd8086
 */
Packit dd8086
driver_return_code_t
Packit dd8086
eject_media_freebsd_ioctl (_img_private_t *p_env)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_obj = p_env;
Packit dd8086
  int ret=DRIVER_OP_ERROR;
Packit dd8086
Packit dd8086
  if (ioctl(p_obj->gen.fd, CDIOCALLOW) == -1) {
Packit dd8086
    cdio_warn("ioctl(fd, CDIOCALLOW) failed: %s\n", strerror(errno));
Packit dd8086
  } else if (ioctl(p_obj->gen.fd, CDIOCEJECT) == -1) {
Packit dd8086
    cdio_warn("ioctl(CDIOCEJECT) failed: %s\n", strerror(errno));
Packit dd8086
  } else {
Packit dd8086
    ret=DRIVER_OP_SUCCESS;;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return ret;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the media catalog number MCN.
Packit dd8086
Packit dd8086
  Note: string is malloc'd so caller should free() then returned
Packit dd8086
  string when done with it.
Packit dd8086
Packit dd8086
  FIXME: This is just a guess.
Packit dd8086
Packit dd8086
 */
Packit dd8086
char *
Packit dd8086
get_mcn_freebsd_ioctl (const _img_private_t *p_env) {
Packit dd8086
Packit dd8086
  struct ioc_read_subchannel subchannel;
Packit dd8086
  struct cd_sub_channel_info subchannel_info;
Packit dd8086
Packit dd8086
  subchannel.address_format = CDIO_CDROM_MSF;
Packit dd8086
  subchannel.data_format    = CDIO_SUBCHANNEL_MEDIA_CATALOG;
Packit dd8086
  subchannel.track          = 0;
Packit dd8086
  subchannel.data_len       = sizeof(subchannel_info);
Packit dd8086
  subchannel.data           = &subchannel_info;
Packit dd8086
Packit dd8086
  if(ioctl(p_env->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) {
Packit dd8086
    perror("CDIOCREADSUBCHANNEL");
Packit dd8086
    return NULL;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* Probably need a loop over tracks rather than give up if we
Packit dd8086
     can't find in track 0.
Packit dd8086
   */
Packit dd8086
  if (subchannel_info.what.media_catalog.mc_valid)
Packit dd8086
    return strdup((char *)subchannel_info.what.media_catalog.mc_number);
Packit dd8086
  else
Packit dd8086
    return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get format of track.
Packit dd8086
Packit dd8086
  FIXME: We're just guessing this from the GNU/Linux code.
Packit dd8086
Packit dd8086
*/
Packit dd8086
track_format_t
Packit dd8086
get_track_format_freebsd_ioctl(const _img_private_t *p_env, track_t i_track)
Packit dd8086
{
Packit dd8086
  struct ioc_read_subchannel subchannel;
Packit dd8086
  struct cd_sub_channel_info subchannel_info;
Packit dd8086
Packit dd8086
  subchannel.address_format = CDIO_CDROM_LBA;
Packit dd8086
  subchannel.data_format    = CDIO_SUBCHANNEL_CURRENT_POSITION;
Packit dd8086
  subchannel.track          = i_track;
Packit dd8086
  subchannel.data_len       = 1;
Packit dd8086
  subchannel.data           = &subchannel_info;
Packit dd8086
Packit dd8086
  if(ioctl(p_env->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) {
Packit dd8086
    perror("CDIOCREADSUBCHANNEL");
Packit dd8086
    return 1;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (subchannel_info.what.position.control == 0x04) {
Packit dd8086
    if (subchannel_info.what.position.data_format == 0x10)
Packit dd8086
      return TRACK_FORMAT_CDI;
Packit dd8086
    else if (subchannel_info.what.position.data_format == 0x20)
Packit dd8086
      return TRACK_FORMAT_XA;
Packit dd8086
    else
Packit dd8086
      return TRACK_FORMAT_DATA;
Packit dd8086
  } else
Packit dd8086
    return TRACK_FORMAT_AUDIO;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return true if we have XA data (green, mode2 form1) or
Packit dd8086
  XA data (green, mode2 form2). That is track begins:
Packit dd8086
  sync - header - subheader
Packit dd8086
  12     4      -  8
Packit dd8086
Packit dd8086
  FIXME: there's gotta be a better design for this and get_track_format?
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
get_track_green_freebsd_ioctl(const _img_private_t *p_env, track_t i_track)
Packit dd8086
{
Packit dd8086
  struct ioc_read_subchannel subchannel;
Packit dd8086
  struct cd_sub_channel_info subchannel_info;
Packit dd8086
Packit dd8086
  subchannel.address_format = CDIO_CDROM_LBA;
Packit dd8086
  subchannel.data_format    = CDIO_SUBCHANNEL_CURRENT_POSITION;
Packit dd8086
  subchannel.track          = i_track;
Packit dd8086
  subchannel.data_len       = 1;
Packit dd8086
  subchannel.data           = &subchannel_info;
Packit dd8086
Packit dd8086
  if(ioctl(p_env->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) {
Packit dd8086
    perror("CDIOCREADSUBCHANNEL");
Packit dd8086
    return 1;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* FIXME: Dunno if this is the right way, but it's what
Packit dd8086
     I was using in cdinfo for a while.
Packit dd8086
   */
Packit dd8086
  return (subchannel_info.what.position.control & 2) != 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
#endif /* HAVE_FREEBSD_CDROM */