summaryrefslogblamecommitdiffstats
path: root/cpukit/libblock/src/blkdev.c
blob: 341bccf4e500d3aab091efff9dce9167b08770fc (plain) (tree)
1
2
3
4
5
6
7
8
9


        

                        


                           
  





                                                        



                   

                   



















                                                                          
                      



                        
                          
 
                                                    
                                

                                    
 

                                          
 


                          
 

                                             
 

                     
                                    

                                 
 




















                                                                           
                                    







                                      

                                  
                      


                         

                         
                          
 
                                                    
                                

                                    
 

                                          
 


                          
 

                                             
 

                     
                                    
                                 
 
                                                   




                                                        
 




                                                            
 


                                                   
 














                                           
                                                          

              
                          
 
                                                    
                                

                                    
 
               
 
                           
 










                                            
                                                          

              
                          
 
                                                    
                                

                                    
 
               
 
                           
 













                                            
                          
           
 
                                                    
                                

                                    
 

                          
                                    

                                                
 
                                 


                                          
                                 


                                                                   
 
                                 
         
                                                     
                                                                            


                                                
 
                
                                                                            



                                                         
 

                            
/**
 * @file
 *
 * @ingroup rtems_blkdev
 *
 * Block device management.
 */
 
/*
 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
 * Author: Victor V. Vengerov <vvv@oktet.ru>
 *
 * @(#) $Id$
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>

#include <rtems.h>
#include <rtems/libio.h>
#include <sys/ioctl.h>

#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_log2;
    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_log2 = dd->block_size_log2;
    block_size = dd->block_size;

    buf = args->buffer;
    count = args->count;
    args->bytes_moved = 0;

    block = args->offset >> block_size_log2;
    blkofs = args->offset & (block_size - 1);

    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;
    int           block_size_log2;
    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_log2 = dd->block_size_log2;
    block_size = dd->block_size;

    buf = args->buffer;
    count = args->count;
    args->bytes_moved = 0;

    block = args->offset >> block_size_log2;
    blkofs = args->offset & (block_size - 1);

    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_GETBLKSIZE:
            args->ioctl_return = dd->block_size;
            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;
}