filename | src/drivers/cdrom/cd_linux.c |
changeset | 1097:d4807997e450 |
prev | 1025:f32183d273fb |
next | 1109:700c5ab26a63 |
author | nkeynes |
date | Sun Jan 31 18:35:06 2010 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Refactor CDROM host support - Completely separate GDROM hardware (in gdrom/gdrom.c) from generic CDROM support (now in drivers/cdrom) - Add concept of 'sector sources' that can be mixed and matched to create cdrom discs (makes support of arbitrary disc types much simpler) |
file | annotate | diff | log | raw |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/drivers/cdrom/cd_linux.c Sun Jan 31 18:35:06 2010 +10001.3 @@ -0,0 +1,179 @@1.4 +/**1.5 + * $Id$1.6 + *1.7 + * Linux cd-rom device driver. Implemented using the SCSI transport.1.8 + *1.9 + * Copyright (c) 2005 Nathan Keynes.1.10 + *1.11 + * This program is free software; you can redistribute it and/or modify1.12 + * it under the terms of the GNU General Public License as published by1.13 + * the Free Software Foundation; either version 2 of the License, or1.14 + * (at your option) any later version.1.15 + *1.16 + * This program is distributed in the hope that it will be useful,1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.19 + * GNU General Public License for more details.1.20 + */1.21 +#include <unistd.h>1.22 +#include <stdlib.h>1.23 +#include <stdio.h>1.24 +#include <string.h>1.25 +#include <errno.h>1.26 +#include <ctype.h>1.27 +#include <linux/cdrom.h>1.28 +#include <sys/stat.h>1.29 +#include <sys/ioctl.h>1.30 +#include <fstab.h>1.31 +#include <fcntl.h>1.32 +1.33 +#include "drivers/cdrom/cdimpl.h"1.34 +1.35 +static gboolean linux_is_cdrom_device( FILE *f );1.36 +static gboolean linux_cdrom_disc_init( cdrom_disc_t disc, ERROR *err );1.37 +static cdrom_disc_t linux_cdrom_drive_open( cdrom_drive_t drive, ERROR *err );1.38 +static cdrom_error_t linux_cdrom_do_cmd( int fd, char *cmd,1.39 + unsigned char *buf, unsigned int *buflen, unsigned char direction );1.40 +static cdrom_error_t linux_packet_read( cdrom_disc_t disc, char *cmd,1.41 + unsigned char *buf, uint32_t *buflen );1.42 +static cdrom_error_t linux_packet_cmd( cdrom_disc_t disc, char *cmd );1.43 +static gboolean linux_media_changed( cdrom_disc_t disc );1.44 +1.45 +1.46 +struct cdrom_disc_factory linux_cdrom_drive_factory = { "Linux", NULL,1.47 + linux_is_cdrom_device, linux_cdrom_disc_init, cdrom_disc_scsi_read_toc };1.48 +1.49 +static struct cdrom_scsi_transport linux_scsi_transport = {1.50 + linux_packet_read, linux_packet_cmd, linux_media_changed };1.51 +1.52 +static gboolean linux_is_cdrom_device( FILE *f )1.53 +{1.54 + int caps = ioctl(fileno(f), CDROM_GET_CAPABILITY);1.55 + if( caps == -1 ) {1.56 + /* Quick check that this is really a CD device */1.57 + return FALSE;1.58 + } else {1.59 + return TRUE;1.60 + }1.61 +}1.62 +1.63 +void cdrom_drive_scan(void)1.64 +{1.65 + unsigned char ident[256];1.66 + uint32_t identlen;1.67 + char cmd[12] = {0x12,0,0,0, 0xFF,0,0,0, 0,0,0,0};1.68 +1.69 + struct fstab *ent;1.70 + struct stat st;1.71 + setfsent();1.72 + while( (ent = getfsent()) != NULL ) {1.73 + if( (stat(ent->fs_spec, &st) != -1) &&1.74 + S_ISBLK(st.st_mode) ) {1.75 + /* Got a valid block device - is it a CDROM? */1.76 + int fd = open(ent->fs_spec, O_RDONLY|O_NONBLOCK);1.77 + if( fd == -1 )1.78 + continue;1.79 + int caps = ioctl(fd, CDROM_GET_CAPABILITY);1.80 + if( caps != -1 ) {1.81 + /* Appears to support CDROM functions */1.82 + identlen = sizeof(ident);1.83 + if( linux_cdrom_do_cmd( fd, cmd, ident, &identlen, CGC_DATA_READ ) ==1.84 + CDROM_ERROR_OK ) {1.85 + const char *drive_name = mmc_parse_inquiry( ident );1.86 + cdrom_drive_add( ent->fs_spec, drive_name, linux_cdrom_drive_open );1.87 + }1.88 + }1.89 + close(fd);1.90 + }1.91 + }1.92 +}1.93 +1.94 +gboolean linux_cdrom_disc_init( cdrom_disc_t disc, ERROR *err )1.95 +{1.96 + if( linux_is_cdrom_device( cdrom_disc_get_base_file(disc) ) ) {1.97 + cdrom_disc_scsi_init(disc, &linux_scsi_transport);1.98 + return TRUE;1.99 + } else {1.100 + return FALSE;1.101 + }1.102 +}1.103 +1.104 +cdrom_disc_t linux_cdrom_drive_open( cdrom_drive_t drive, ERROR *err )1.105 +{1.106 +1.107 + int fd = open(drive->name, O_RDONLY|O_NONBLOCK);1.108 + if( fd == -1 ) {1.109 + SET_ERROR(err, errno, "Unable to open device '%s': %s", drive->name, strerror(errno) );1.110 + return NULL;1.111 + } else {1.112 + FILE *f = fdopen(fd,"ro");1.113 + if( !linux_is_cdrom_device(f) ) {1.114 + SET_ERROR(err, EINVAL, "Device '%s' is not a CDROM drive", drive->name );1.115 + return NULL;1.116 + }1.117 + return cdrom_disc_scsi_new_file(f, drive->name, &linux_scsi_transport, err);1.118 + }1.119 +}1.120 +1.121 +static gboolean linux_media_changed( cdrom_disc_t disc )1.122 +{1.123 + int fd = cdrom_disc_get_base_fd(disc);1.124 + int status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);1.125 + if( status == CDS_DISC_OK ) {1.126 + status = ioctl(fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT);1.127 + return status == 0 ? FALSE : TRUE;1.128 + } else {1.129 + return disc->disc_type == CDROM_DISC_NONE ? FALSE : TRUE;1.130 + }1.131 +}1.132 +1.133 +static cdrom_error_t linux_cdrom_do_cmd( int fd, char *cmd,1.134 + unsigned char *buffer, unsigned int *buflen,1.135 + unsigned char direction )1.136 +{1.137 + struct request_sense sense;1.138 + struct cdrom_generic_command cgc;1.139 +1.140 + memset( &cgc, 0, sizeof(cgc) );1.141 + memset( &sense, 0, sizeof(sense) );1.142 + memcpy( cgc.cmd, cmd, 12 );1.143 + cgc.buffer = buffer;1.144 + if( buflen == NULL )1.145 + cgc.buflen = 0;1.146 + else1.147 + cgc.buflen = *buflen;1.148 + cgc.sense = &sense;1.149 + cgc.data_direction = direction;1.150 +1.151 + if( ioctl(fd, CDROM_SEND_PACKET, &cgc) < 0 ) {1.152 + if( sense.sense_key == 0 ) {1.153 + return -1;1.154 + } else {1.155 + return sense.sense_key | (sense.asc<<8);1.156 + }1.157 + } else {1.158 + if( buflen != NULL )1.159 + *buflen = cgc.buflen;1.160 + return CDROM_ERROR_OK;1.161 + }1.162 +1.163 +}1.164 +1.165 +/**1.166 + * Send a packet command to the device and wait for a response.1.167 + * @return 0 on success, -1 on an operating system error, or a sense error1.168 + * code on a device error.1.169 + */1.170 +static cdrom_error_t linux_packet_read( cdrom_disc_t disc, char *cmd,1.171 + unsigned char *buffer, unsigned int *buflen )1.172 +{1.173 + int fd = cdrom_disc_get_base_fd(disc);1.174 + return linux_cdrom_do_cmd( fd, cmd, buffer, buflen, CGC_DATA_READ );1.175 +}1.176 +1.177 +static cdrom_error_t linux_packet_cmd( cdrom_disc_t disc, char *cmd )1.178 +{1.179 + int fd = cdrom_disc_get_base_fd(disc);1.180 + return linux_cdrom_do_cmd( fd, cmd, NULL, NULL, CGC_DATA_NONE );1.181 +}1.182 +
.