Search
lxdream.org :: lxdream/src/drivers/cdrom/cd_linux.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/cd_linux.c
changeset 1109:700c5ab26a63
prev1097:d4807997e450
author nkeynes
date Wed Jan 19 17:50:09 2011 +1000 (13 years ago)
permissions -rw-r--r--
last change Implement vertex array range support, and move buffer operations to gl_vbo.c
file annotate diff log raw
nkeynes@520
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@520
     3
 *
nkeynes@1023
     4
 * Linux cd-rom device driver. Implemented using the SCSI transport.
nkeynes@520
     5
 *
nkeynes@520
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@520
     7
 *
nkeynes@520
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@520
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@520
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@520
    11
 * (at your option) any later version.
nkeynes@520
    12
 *
nkeynes@520
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@520
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@520
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@520
    16
 * GNU General Public License for more details.
nkeynes@520
    17
 */
nkeynes@520
    18
#include <unistd.h>
nkeynes@520
    19
#include <stdlib.h>
nkeynes@520
    20
#include <stdio.h>
nkeynes@520
    21
#include <string.h>
nkeynes@520
    22
#include <errno.h>
nkeynes@806
    23
#include <ctype.h>
nkeynes@520
    24
#include <linux/cdrom.h>
nkeynes@520
    25
#include <sys/stat.h>
nkeynes@520
    26
#include <sys/ioctl.h>
nkeynes@520
    27
#include <fstab.h>
nkeynes@520
    28
#include <fcntl.h>
nkeynes@520
    29
nkeynes@1097
    30
#include "drivers/cdrom/cdimpl.h"
nkeynes@520
    31
nkeynes@1023
    32
static gboolean linux_is_cdrom_device( FILE *f );
nkeynes@1097
    33
static gboolean linux_cdrom_disc_init( cdrom_disc_t disc, ERROR *err );
nkeynes@1097
    34
static cdrom_disc_t linux_cdrom_drive_open( cdrom_drive_t drive, ERROR *err );
nkeynes@1097
    35
static cdrom_error_t linux_cdrom_do_cmd( int fd, char *cmd,
nkeynes@1097
    36
        unsigned char *buf, unsigned int *buflen, unsigned char direction );
nkeynes@1097
    37
static cdrom_error_t linux_packet_read( cdrom_disc_t disc, char *cmd,
nkeynes@1023
    38
                                        unsigned char *buf, uint32_t *buflen );
nkeynes@1097
    39
static cdrom_error_t linux_packet_cmd( cdrom_disc_t disc, char *cmd );
nkeynes@1097
    40
static gboolean linux_media_changed( cdrom_disc_t disc );
nkeynes@520
    41
nkeynes@520
    42
nkeynes@1097
    43
struct cdrom_disc_factory linux_cdrom_drive_factory = { "Linux", NULL,
nkeynes@1097
    44
        linux_is_cdrom_device, linux_cdrom_disc_init, cdrom_disc_scsi_read_toc };
nkeynes@1023
    45
        
nkeynes@1097
    46
static struct cdrom_scsi_transport linux_scsi_transport = {
nkeynes@1023
    47
	linux_packet_read, linux_packet_cmd, linux_media_changed };
nkeynes@1023
    48
        
nkeynes@1023
    49
static gboolean linux_is_cdrom_device( FILE *f )
nkeynes@1023
    50
{
nkeynes@1023
    51
    int caps = ioctl(fileno(f), CDROM_GET_CAPABILITY);
nkeynes@1023
    52
    if( caps == -1 ) {
nkeynes@1023
    53
        /* Quick check that this is really a CD device */
nkeynes@1023
    54
        return FALSE;
nkeynes@1023
    55
    } else {
nkeynes@1023
    56
    	return TRUE;
nkeynes@1023
    57
    }
nkeynes@1023
    58
}		
nkeynes@1023
    59
nkeynes@1097
    60
void cdrom_drive_scan(void)
nkeynes@520
    61
{
nkeynes@1097
    62
    unsigned char ident[256];
nkeynes@1097
    63
    uint32_t identlen;
nkeynes@1097
    64
    char cmd[12] = {0x12,0,0,0, 0xFF,0,0,0, 0,0,0,0};
nkeynes@1097
    65
    
nkeynes@520
    66
    struct fstab *ent;
nkeynes@520
    67
    struct stat st;
nkeynes@520
    68
    setfsent();
nkeynes@520
    69
    while( (ent = getfsent()) != NULL ) {
nkeynes@736
    70
        if( (stat(ent->fs_spec, &st) != -1) && 
nkeynes@736
    71
                S_ISBLK(st.st_mode) ) {
nkeynes@736
    72
            /* Got a valid block device - is it a CDROM? */
nkeynes@736
    73
            int fd = open(ent->fs_spec, O_RDONLY|O_NONBLOCK);
nkeynes@736
    74
            if( fd == -1 )
nkeynes@736
    75
                continue;
nkeynes@736
    76
            int caps = ioctl(fd, CDROM_GET_CAPABILITY);
nkeynes@736
    77
            if( caps != -1 ) {
nkeynes@736
    78
                /* Appears to support CDROM functions */
nkeynes@1097
    79
                identlen = sizeof(ident);
nkeynes@1097
    80
                if( linux_cdrom_do_cmd( fd, cmd, ident, &identlen, CGC_DATA_READ ) ==
nkeynes@1097
    81
                        CDROM_ERROR_OK ) {
nkeynes@1097
    82
                    const char *drive_name = mmc_parse_inquiry( ident );
nkeynes@1097
    83
                    cdrom_drive_add( ent->fs_spec, drive_name, linux_cdrom_drive_open );
nkeynes@1023
    84
                }
nkeynes@736
    85
            }
nkeynes@1097
    86
            close(fd);
nkeynes@736
    87
        }
nkeynes@520
    88
    }
nkeynes@520
    89
}
nkeynes@520
    90
nkeynes@1097
    91
gboolean linux_cdrom_disc_init( cdrom_disc_t disc, ERROR *err )
nkeynes@709
    92
{
nkeynes@1097
    93
    if( linux_is_cdrom_device( cdrom_disc_get_base_file(disc) ) ) {
nkeynes@1097
    94
        cdrom_disc_scsi_init(disc, &linux_scsi_transport);
nkeynes@1097
    95
        return TRUE;
nkeynes@1097
    96
    } else {
nkeynes@1097
    97
        return FALSE;
nkeynes@1097
    98
    }
nkeynes@709
    99
}
nkeynes@709
   100
nkeynes@1097
   101
cdrom_disc_t linux_cdrom_drive_open( cdrom_drive_t drive, ERROR *err )
nkeynes@520
   102
{
nkeynes@1097
   103
    
nkeynes@1097
   104
    int fd = open(drive->name, O_RDONLY|O_NONBLOCK);
nkeynes@1097
   105
    if( fd == -1 ) {
nkeynes@1109
   106
        SET_ERROR(err, LX_ERR_FILE_NOOPEN, "Unable to open device '%s': %s", drive->name, strerror(errno) );
nkeynes@1097
   107
        return NULL;
nkeynes@1097
   108
    } else {
nkeynes@1097
   109
        FILE *f = fdopen(fd,"ro");
nkeynes@1097
   110
        if( !linux_is_cdrom_device(f) ) {
nkeynes@1109
   111
            SET_ERROR(err, LX_ERR_FILE_UNKNOWN, "Device '%s' is not a CDROM drive", drive->name );
nkeynes@1097
   112
            return NULL;
nkeynes@1097
   113
        }
nkeynes@1097
   114
        return cdrom_disc_scsi_new_file(f, drive->name, &linux_scsi_transport, err);
nkeynes@1097
   115
    }
nkeynes@520
   116
}
nkeynes@520
   117
nkeynes@1097
   118
static gboolean linux_media_changed( cdrom_disc_t disc )
nkeynes@520
   119
{
nkeynes@1097
   120
    int fd = cdrom_disc_get_base_fd(disc);
nkeynes@520
   121
    int status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
nkeynes@520
   122
    if( status == CDS_DISC_OK ) {
nkeynes@736
   123
        status = ioctl(fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT);
nkeynes@1023
   124
        return status == 0 ? FALSE : TRUE;
nkeynes@520
   125
    } else {
nkeynes@1097
   126
    	return disc->disc_type == CDROM_DISC_NONE ? FALSE : TRUE;
nkeynes@520
   127
    }
nkeynes@520
   128
}
nkeynes@520
   129
nkeynes@1097
   130
static cdrom_error_t linux_cdrom_do_cmd( int fd, char *cmd,
nkeynes@1097
   131
        unsigned char *buffer, unsigned int *buflen, 
nkeynes@1097
   132
        unsigned char direction )
nkeynes@1097
   133
{
nkeynes@1097
   134
    struct request_sense sense;
nkeynes@1097
   135
    struct cdrom_generic_command cgc;
nkeynes@1097
   136
nkeynes@1097
   137
    memset( &cgc, 0, sizeof(cgc) );
nkeynes@1097
   138
    memset( &sense, 0, sizeof(sense) );
nkeynes@1097
   139
    memcpy( cgc.cmd, cmd, 12 );
nkeynes@1097
   140
    cgc.buffer = buffer;
nkeynes@1097
   141
    if( buflen == NULL )
nkeynes@1097
   142
        cgc.buflen = 0;
nkeynes@1097
   143
    else
nkeynes@1097
   144
        cgc.buflen = *buflen;
nkeynes@1097
   145
    cgc.sense = &sense;
nkeynes@1097
   146
    cgc.data_direction = direction;
nkeynes@1097
   147
nkeynes@1097
   148
    if( ioctl(fd, CDROM_SEND_PACKET, &cgc) < 0 ) {
nkeynes@1097
   149
        if( sense.sense_key == 0 ) {
nkeynes@1097
   150
            return -1; 
nkeynes@1097
   151
        } else {
nkeynes@1097
   152
            return sense.sense_key | (sense.asc<<8);
nkeynes@1097
   153
        }
nkeynes@1097
   154
    } else {
nkeynes@1097
   155
        if( buflen != NULL )
nkeynes@1097
   156
            *buflen = cgc.buflen;
nkeynes@1097
   157
        return CDROM_ERROR_OK;
nkeynes@1097
   158
    }
nkeynes@1097
   159
    
nkeynes@1097
   160
}
nkeynes@1097
   161
nkeynes@520
   162
/**
nkeynes@520
   163
 * Send a packet command to the device and wait for a response. 
nkeynes@520
   164
 * @return 0 on success, -1 on an operating system error, or a sense error
nkeynes@520
   165
 * code on a device error.
nkeynes@520
   166
 */
nkeynes@1097
   167
static cdrom_error_t linux_packet_read( cdrom_disc_t disc, char *cmd,
nkeynes@1097
   168
                                        unsigned char *buffer, unsigned int *buflen )
nkeynes@520
   169
{
nkeynes@1097
   170
    int fd = cdrom_disc_get_base_fd(disc);
nkeynes@1097
   171
    return linux_cdrom_do_cmd( fd, cmd, buffer, buflen, CGC_DATA_READ );
nkeynes@520
   172
}
nkeynes@1023
   173
nkeynes@1097
   174
static cdrom_error_t linux_packet_cmd( cdrom_disc_t disc, char *cmd )
nkeynes@1023
   175
{
nkeynes@1097
   176
    int fd = cdrom_disc_get_base_fd(disc);
nkeynes@1097
   177
    return linux_cdrom_do_cmd( fd, cmd, NULL, NULL, CGC_DATA_NONE );
nkeynes@1097
   178
}
nkeynes@1023
   179
.