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