filename | src/drivers/cdrom/cd_linux.c |
changeset | 1109:700c5ab26a63 |
prev | 1097: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 }
.