/** * @file * * @ingroup rtems_blkdev * * Block device management. */ /* * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia * Author: Victor V. Vengerov * * @(#) $Id$ */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "rtems/diskdevs.h" #include "rtems/bdbuf.h" /* rtems_blkdev_generic_read -- * Generic block device read primitive. Implemented using block device * buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_read( rtems_device_major_number major, rtems_device_minor_number minor, void * arg) { rtems_libio_rw_args_t *args = arg; int block_size; char *buf; unsigned int count; unsigned int block; unsigned int blkofs; dev_t dev; rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; block_size = dd->block_size; buf = args->buffer; count = args->count; args->bytes_moved = 0; block = args->offset / block_size; blkofs = args->offset % block_size; while (count > 0) { rtems_bdbuf_buffer *diskbuf; uint32_t copy; rtems_status_code rc; rc = rtems_bdbuf_read(dev, block, &diskbuf); if (rc != RTEMS_SUCCESSFUL) return rc; copy = block_size - blkofs; if (copy > count) copy = count; memcpy(buf, (char *)diskbuf->buffer + blkofs, copy); rc = rtems_bdbuf_release(diskbuf); args->bytes_moved += copy; if (rc != RTEMS_SUCCESSFUL) return rc; count -= copy; buf += copy; blkofs = 0; block++; } return RTEMS_SUCCESSFUL; } /* rtems_blkdev_generic_write -- * Generic block device write primitive. Implemented using block device * buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_write( rtems_device_major_number major, rtems_device_minor_number minor, void * arg) { rtems_libio_rw_args_t *args = arg; uint32_t block_size; char *buf; uint32_t count; uint32_t block; uint32_t blkofs; dev_t dev; rtems_status_code rc; rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; block_size = dd->block_size; buf = args->buffer; count = args->count; args->bytes_moved = 0; block = args->offset / block_size; blkofs = args->offset % block_size; while (count > 0) { rtems_bdbuf_buffer *diskbuf; uint32_t copy; if ((blkofs == 0) && (count >= block_size)) rc = rtems_bdbuf_get(dev, block, &diskbuf); else rc = rtems_bdbuf_read(dev, block, &diskbuf); if (rc != RTEMS_SUCCESSFUL) return rc; copy = block_size - blkofs; if (copy > count) copy = count; memcpy((char *)diskbuf->buffer + blkofs, buf, copy); args->bytes_moved += copy; rc = rtems_bdbuf_release_modified(diskbuf); if (rc != RTEMS_SUCCESSFUL) return rc; count -= copy; buf += copy; blkofs = 0; block++; } return RTEMS_SUCCESSFUL; } /* blkdev_generic_open -- * Generic block device open primitive. */ rtems_device_driver rtems_blkdev_generic_open( rtems_device_major_number major, rtems_device_minor_number minor, void * arg __attribute__((unused))) { dev_t dev; rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; dd->uses++; rtems_disk_release(dd); return RTEMS_SUCCESSFUL; } /* blkdev_generic_close -- * Generic block device close primitive. */ rtems_device_driver rtems_blkdev_generic_close( rtems_device_major_number major, rtems_device_minor_number minor, void * arg __attribute__((unused))) { dev_t dev; rtems_disk_device *dd; dev = rtems_filesystem_make_dev_t(major, minor); dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; dd->uses--; rtems_disk_release(dd); return RTEMS_SUCCESSFUL; } /* blkdev_generic_ioctl -- * Generic block device ioctl primitive. */ rtems_device_driver rtems_blkdev_generic_ioctl( rtems_device_major_number major, rtems_device_minor_number minor, void * arg) { rtems_libio_ioctl_args_t *args = arg; dev_t dev; rtems_disk_device *dd; int rc; dev = rtems_filesystem_make_dev_t(major, minor); dd = rtems_disk_obtain(dev); if (dd == NULL) return RTEMS_INVALID_NUMBER; switch (args->command) { case RTEMS_BLKIO_GETMEDIABLKSIZE: args->ioctl_return = dd->media_block_size; break; case RTEMS_BLKIO_GETBLKSIZE: args->ioctl_return = dd->block_size; break; case RTEMS_BLKIO_SETBLKSIZE: dd->block_size = *((size_t*) args->buffer); break; case RTEMS_BLKIO_GETSIZE: args->ioctl_return = dd->size; break; case RTEMS_BLKIO_SYNCDEV: rc = rtems_bdbuf_syncdev(dd->dev); args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1); break; case RTEMS_BLKIO_REQUEST: { rtems_blkdev_request *req = args->buffer; args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command, req); break; } default: args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command, args->buffer); break; } rtems_disk_release(dd); return RTEMS_SUCCESSFUL; } int rtems_blkdev_ioctl(dev_t dev, uint32_t req, void *argp) { rtems_disk_device *dd; size_t *arg_size = argp; dd = rtems_disk_obtain(dev); if (dd == NULL) { errno = ENODEV; return -1; } switch (req) { case RTEMS_BLKIO_GETMEDIABLKSIZE: *arg_size = dd->media_block_size; break; case RTEMS_BLKIO_GETBLKSIZE: *arg_size = dd->block_size; break; case RTEMS_BLKIO_SETBLKSIZE: dd->block_size = *arg_size; break; case RTEMS_BLKIO_GETSIZE: *arg_size = dd->size; break; default: errno = EINVAL; return -1; break; } rtems_disk_release(dd); return 0; }