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@678 | 30 | #include "gdrom/gddriver.h"
|
nkeynes@520 | 31 | #include "gdrom/packet.h"
|
nkeynes@520 | 32 | #include "dream.h"
|
nkeynes@520 | 33 |
|
nkeynes@1023 | 34 | static gboolean linux_is_cdrom_device( FILE *f );
|
nkeynes@1023 | 35 | static gdrom_disc_t linux_open_device( const gchar *filename, FILE *f );
|
nkeynes@1025 | 36 | static gdrom_error_t linux_packet_read( gdrom_disc_t disc, char *cmd,
|
nkeynes@1023 | 37 | unsigned char *buf, uint32_t *buflen );
|
nkeynes@1025 | 38 | static gdrom_error_t linux_packet_cmd( gdrom_disc_t disc, char *cmd );
|
nkeynes@1023 | 39 | static gboolean linux_media_changed( gdrom_disc_t disc );
|
nkeynes@520 | 40 |
|
nkeynes@520 | 41 |
|
nkeynes@520 | 42 | struct gdrom_image_class cdrom_device_class = { "Linux", NULL,
|
nkeynes@1023 | 43 | linux_is_cdrom_device, linux_open_device };
|
nkeynes@1023 | 44 |
|
nkeynes@1023 | 45 | static struct gdrom_scsi_transport linux_scsi_transport = {
|
nkeynes@1023 | 46 | linux_packet_read, linux_packet_cmd, linux_media_changed };
|
nkeynes@1023 | 47 |
|
nkeynes@1023 | 48 | static gboolean linux_is_cdrom_device( FILE *f )
|
nkeynes@1023 | 49 | {
|
nkeynes@1023 | 50 | int caps = ioctl(fileno(f), CDROM_GET_CAPABILITY);
|
nkeynes@1023 | 51 | if( caps == -1 ) {
|
nkeynes@1023 | 52 | /* Quick check that this is really a CD device */
|
nkeynes@1023 | 53 | return FALSE;
|
nkeynes@1023 | 54 | } else {
|
nkeynes@1023 | 55 | return TRUE;
|
nkeynes@1023 | 56 | }
|
nkeynes@1023 | 57 | }
|
nkeynes@1023 | 58 |
|
nkeynes@709 | 59 | GList *cdrom_get_native_devices(void)
|
nkeynes@520 | 60 | {
|
nkeynes@520 | 61 | GList *list = NULL;
|
nkeynes@520 | 62 | struct fstab *ent;
|
nkeynes@520 | 63 | struct stat st;
|
nkeynes@520 | 64 | setfsent();
|
nkeynes@520 | 65 | while( (ent = getfsent()) != NULL ) {
|
nkeynes@736 | 66 | if( (stat(ent->fs_spec, &st) != -1) &&
|
nkeynes@736 | 67 | S_ISBLK(st.st_mode) ) {
|
nkeynes@736 | 68 | /* Got a valid block device - is it a CDROM? */
|
nkeynes@736 | 69 | int fd = open(ent->fs_spec, O_RDONLY|O_NONBLOCK);
|
nkeynes@736 | 70 | if( fd == -1 )
|
nkeynes@736 | 71 | continue;
|
nkeynes@736 | 72 | int caps = ioctl(fd, CDROM_GET_CAPABILITY);
|
nkeynes@736 | 73 | if( caps != -1 ) {
|
nkeynes@736 | 74 | /* Appears to support CDROM functions */
|
nkeynes@1023 | 75 | FILE *f = fdopen(fd,"r");
|
nkeynes@1023 | 76 | gdrom_disc_t disc = gdrom_scsi_disc_new(ent->fs_spec, f, &linux_scsi_transport);
|
nkeynes@1023 | 77 | if( disc != NULL ) {
|
nkeynes@1023 | 78 | list = g_list_append( list, gdrom_device_new(disc->name, disc->display_name) );
|
nkeynes@1023 | 79 | disc->destroy(disc,TRUE);
|
nkeynes@1023 | 80 | } else {
|
nkeynes@1023 | 81 | close(fd);
|
nkeynes@1023 | 82 | }
|
nkeynes@1023 | 83 | } else {
|
nkeynes@1023 | 84 | close(fd);
|
nkeynes@736 | 85 | }
|
nkeynes@736 | 86 | }
|
nkeynes@520 | 87 | }
|
nkeynes@520 | 88 | return list;
|
nkeynes@520 | 89 | }
|
nkeynes@520 | 90 |
|
nkeynes@709 | 91 | gdrom_disc_t cdrom_open_device( const gchar *method, const gchar *path )
|
nkeynes@709 | 92 | {
|
nkeynes@709 | 93 | return NULL;
|
nkeynes@709 | 94 | }
|
nkeynes@709 | 95 |
|
nkeynes@1023 | 96 | static gdrom_disc_t linux_open_device( const gchar *filename, FILE *f )
|
nkeynes@520 | 97 | {
|
nkeynes@1023 | 98 | if( !linux_is_cdrom_device(f) ) {
|
nkeynes@1023 | 99 | return NULL;
|
nkeynes@1023 | 100 | }
|
nkeynes@520 | 101 |
|
nkeynes@1023 | 102 | return gdrom_scsi_disc_new(filename, f, &linux_scsi_transport);
|
nkeynes@520 | 103 | }
|
nkeynes@520 | 104 |
|
nkeynes@1023 | 105 | static gboolean linux_media_changed( gdrom_disc_t disc )
|
nkeynes@520 | 106 | {
|
nkeynes@1023 | 107 | int fd = fileno(disc->file);
|
nkeynes@520 | 108 | int status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
|
nkeynes@520 | 109 | if( status == CDS_DISC_OK ) {
|
nkeynes@736 | 110 | status = ioctl(fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT);
|
nkeynes@1023 | 111 | return status == 0 ? FALSE : TRUE;
|
nkeynes@520 | 112 | } else {
|
nkeynes@1023 | 113 | return disc->disc_type == IDE_DISC_NONE ? FALSE : TRUE;
|
nkeynes@520 | 114 | }
|
nkeynes@520 | 115 | }
|
nkeynes@520 | 116 |
|
nkeynes@520 | 117 | /**
|
nkeynes@520 | 118 | * Send a packet command to the device and wait for a response.
|
nkeynes@520 | 119 | * @return 0 on success, -1 on an operating system error, or a sense error
|
nkeynes@520 | 120 | * code on a device error.
|
nkeynes@520 | 121 | */
|
nkeynes@1025 | 122 | static gdrom_error_t linux_packet_read( gdrom_disc_t disc, char *cmd,
|
nkeynes@1023 | 123 | unsigned char *buffer, uint32_t *buflen )
|
nkeynes@520 | 124 | {
|
nkeynes@1023 | 125 | int fd = fileno(disc->file);
|
nkeynes@520 | 126 | struct request_sense sense;
|
nkeynes@520 | 127 | struct cdrom_generic_command cgc;
|
nkeynes@520 | 128 |
|
nkeynes@520 | 129 | memset( &cgc, 0, sizeof(cgc) );
|
nkeynes@520 | 130 | memset( &sense, 0, sizeof(sense) );
|
nkeynes@520 | 131 | memcpy( cgc.cmd, cmd, 12 );
|
nkeynes@520 | 132 | cgc.buffer = buffer;
|
nkeynes@520 | 133 | cgc.buflen = *buflen;
|
nkeynes@520 | 134 | cgc.sense = &sense;
|
nkeynes@1023 | 135 | cgc.data_direction = CGC_DATA_READ;
|
nkeynes@736 | 136 |
|
nkeynes@644 | 137 | if( ioctl(fd, CDROM_SEND_PACKET, &cgc) < 0 ) {
|
nkeynes@736 | 138 | if( sense.sense_key == 0 ) {
|
nkeynes@736 | 139 | return -1;
|
nkeynes@736 | 140 | } else {
|
nkeynes@736 | 141 | /* TODO: Map newer codes back to the ones used by the gd-rom. */
|
nkeynes@736 | 142 | return sense.sense_key | (sense.asc<<8);
|
nkeynes@736 | 143 | }
|
nkeynes@520 | 144 | } else {
|
nkeynes@736 | 145 | *buflen = cgc.buflen;
|
nkeynes@736 | 146 | return 0;
|
nkeynes@520 | 147 | }
|
nkeynes@520 | 148 | }
|
nkeynes@1023 | 149 |
|
nkeynes@1025 | 150 | static gdrom_error_t linux_packet_cmd( gdrom_disc_t disc, char *cmd )
|
nkeynes@1023 | 151 | {
|
nkeynes@1023 | 152 | int fd = fileno(disc->file);
|
nkeynes@1023 | 153 | struct request_sense sense;
|
nkeynes@1023 | 154 | struct cdrom_generic_command cgc;
|
nkeynes@1023 | 155 |
|
nkeynes@1023 | 156 | memset( &cgc, 0, sizeof(cgc) );
|
nkeynes@1023 | 157 | memset( &sense, 0, sizeof(sense) );
|
nkeynes@1023 | 158 | memcpy( cgc.cmd, cmd, 12 );
|
nkeynes@1023 | 159 | cgc.buffer = 0;
|
nkeynes@1023 | 160 | cgc.buflen = 0;
|
nkeynes@1023 | 161 | cgc.sense = &sense;
|
nkeynes@1023 | 162 | cgc.data_direction = CGC_DATA_NONE;
|
nkeynes@1023 | 163 |
|
nkeynes@1023 | 164 | if( ioctl(fd, CDROM_SEND_PACKET, &cgc) < 0 ) {
|
nkeynes@1023 | 165 | if( sense.sense_key == 0 ) {
|
nkeynes@1023 | 166 | return -1;
|
nkeynes@1023 | 167 | } else {
|
nkeynes@1023 | 168 | /* TODO: Map newer codes back to the ones used by the gd-rom. */
|
nkeynes@1023 | 169 | return sense.sense_key | (sense.asc<<8);
|
nkeynes@1023 | 170 | }
|
nkeynes@1023 | 171 | } else {
|
nkeynes@1023 | 172 | return 0;
|
nkeynes@1023 | 173 | }
|
nkeynes@1023 | 174 | }
|