#ifdef __FreeBSD__
#include <signal.h>
#include <sys/disk.h>
+#include <sys/cdio.h>
#endif
#ifdef __OpenBSD__
int fd_got_error;
int fd_media_changed;
#endif
+#if defined(__FreeBSD__)
+ int cd_open_flags;
+#endif
uint8_t* aligned_buf;
} BDRVRawState;
static int fd_open(BlockDriverState *bs);
+#if defined(__FreeBSD__)
+static int cd_open(BlockDriverState *bs);
+#endif
+
+static int raw_is_inserted(BlockDriverState *bs);
+
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
return raw_pread_aligned(bs, offset, buf, count) + sum;
}
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors)
+{
+ int ret;
+
+ ret = raw_pread(bs, sector_num * 512, buf, nb_sectors * 512);
+ if (ret == (nb_sectors * 512))
+ ret = 0;
+ return ret;
+}
+
/*
* offset and count are in bytes and possibly not aligned. For files opened
* with O_DIRECT, necessary alignments are ensured before calling
return raw_pwrite_aligned(bs, offset, buf, count) + sum;
}
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ int ret;
+ ret = raw_pwrite(bs, sector_num * 512, buf, nb_sectors * 512);
+ if (ret == (nb_sectors * 512))
+ ret = 0;
+ return ret;
+}
+
#ifdef CONFIG_AIO
/***********************************************************/
/* Unix AIO using POSIX AIO */
int64_t size;
#ifdef HOST_BSD
struct stat sb;
+#ifdef __FreeBSD__
+ int reopened = 0;
+#endif
#endif
#ifdef __sun__
struct dk_minfo minfo;
return ret;
#ifdef HOST_BSD
+#ifdef __FreeBSD__
+again:
+#endif
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
#else
size = lseek(fd, 0LL, SEEK_END);
#endif
+#ifdef __FreeBSD__
+ switch(s->type) {
+ case FTYPE_CD:
+ /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
+ if (size == 2048LL * (unsigned)-1)
+ size = 0;
+ /* XXX no disc? maybe we need to reopen... */
+ if (size <= 0 && !reopened && cd_open(bs) >= 0) {
+ reopened = 1;
+ goto again;
+ }
+ }
+#endif
} else
#endif
#ifdef __sun__
.aiocb_size = sizeof(RawAIOCB),
#endif
- .bdrv_pread = raw_pread,
- .bdrv_pwrite = raw_pwrite,
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
};
bs->sg = 1;
}
#endif
+#if defined(__FreeBSD__)
+ if (strstart(filename, "/dev/cd", NULL) ||
+ strstart(filename, "/dev/acd", NULL)) {
+ s->type = FTYPE_CD;
+ s->cd_open_flags = open_flags;
+ }
+#endif
+ s->fd = -1;
fd = open(filename, open_flags, 0644);
if (fd < 0) {
ret = -errno;
return ret;
}
s->fd = fd;
+#if defined(__FreeBSD__)
+ /* make sure the door isnt locked at this time */
+ if (s->type == FTYPE_CD)
+ ioctl (s->fd, CDIOCALLOW);
+#endif
#if defined(__linux__)
/* close fd so that we can reopen it as needed */
if (s->type == FTYPE_FD) {
return ioctl(s->fd, req, buf);
}
-#else
+
+static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+ unsigned long int req, void *buf,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ acb = raw_aio_setup(bs, 0, buf, 0, cb, opaque);
+ if (!acb)
+ return NULL;
+
+ acb->aiocb.aio_ioctl_cmd = req;
+ if (qemu_paio_ioctl(&acb->aiocb) < 0) {
+ raw_aio_remove(acb);
+ return NULL;
+ }
+
+ return &acb->common;
+}
+
+#elif defined(__FreeBSD__)
+
+static int fd_open(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+
+ /* this is just to ensure s->fd is sane (its called by io ops) */
+ if (s->fd >= 0)
+ return 0;
+ return -EIO;
+}
+
+static int cd_open(BlockDriverState *bs)
+{
+#if defined(__FreeBSD__)
+ BDRVRawState *s = bs->opaque;
+ int fd;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ /* XXX force reread of possibly changed/newly loaded disc,
+ * FreeBSD seems to not notice sometimes... */
+ if (s->fd >= 0)
+ close (s->fd);
+ fd = open(bs->filename, s->cd_open_flags, 0644);
+ if (fd < 0) {
+ s->fd = -1;
+ return -EIO;
+ }
+ s->fd = fd;
+ /* make sure the door isnt locked at this time */
+ ioctl (s->fd, CDIOCALLOW);
+ }
+#endif
+ return 0;
+}
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ return (raw_getlength(bs) > 0);
+ case FTYPE_FD:
+ /* XXX handle this */
+ /* FALLTHRU */
+ default:
+ return 1;
+ }
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+ return -ENOTSUP;
+}
+
+static int raw_eject(BlockDriverState *bs, int eject_flag)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (s->fd < 0)
+ return -ENOTSUP;
+ (void) ioctl (s->fd, CDIOCALLOW);
+ if (eject_flag) {
+ if (ioctl (s->fd, CDIOCEJECT) < 0)
+ perror("CDIOCEJECT");
+ } else {
+ if (ioctl (s->fd, CDIOCCLOSE) < 0)
+ perror("CDIOCCLOSE");
+ }
+ if (cd_open(bs) < 0)
+ return -ENOTSUP;
+ break;
+ case FTYPE_FD:
+ /* XXX handle this */
+ /* FALLTHRU */
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int raw_set_locked(BlockDriverState *bs, int locked)
+{
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (s->fd < 0)
+ return -ENOTSUP;
+ if (ioctl (s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
+ /* Note: an error can happen if the distribution automatically
+ mounts the CD-ROM */
+ // perror("CDROM_LOCKDOOR");
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+{
+ return -ENOTSUP;
+}
+#else /* !linux && !FreeBSD */
static int fd_open(BlockDriverState *bs)
{
{
return -ENOTSUP;
}
-#endif /* !linux */
+
+static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+ unsigned long int req, void *buf,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ return -ENOTSUP;
+}
+#endif /* !linux && !FreeBSD */
BlockDriver bdrv_host_device = {
.format_name = "host_device",
.aiocb_size = sizeof(RawAIOCB),
#endif
- .bdrv_pread = raw_pread,
- .bdrv_pwrite = raw_pwrite,
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
.bdrv_getlength = raw_getlength,
/* removable device support */
.bdrv_set_locked = raw_set_locked,
/* generic scsi device */
.bdrv_ioctl = raw_ioctl,
+ .bdrv_aio_ioctl = raw_aio_ioctl,
};