00001
00002
00003
00004
00005
00006
00007
00008
00009 #define CREAM_ON_ERRNO(s) do { \
00010 switch ((s)[2]&0x0F) \
00011 { case 2: if ((s)[12]==4) errno=EAGAIN; break; \
00012 case 5: errno=EINVAL; \
00013 if ((s)[13]==0) \
00014 { if ((s)[12]==0x21) errno=ENOSPC; \
00015 else if ((s)[12]==0x20) errno=ENODEV; \
00016 } \
00017 break; \
00018 } \
00019 } while(0)
00020 #define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13]))
00021 #define SK(errcode) (((errcode)>>16)&0xF)
00022 #define ASC(errcode) (((errcode)>>8)&0xFF)
00023 #define ASCQ(errcode) ((errcode)&0xFF)
00024
00025 #ifndef _LARGEFILE_SOURCE
00026 #define _LARGEFILE_SOURCE
00027 #endif
00028 #ifndef _LARGEFILE64_SOURCE
00029 #define _LARGEFILE64_SOURCE
00030 #endif
00031 #ifndef _FILE_OFFSET_BITS
00032 #define _FILE_OFFSET_BITS 64
00033 #endif
00034 #ifndef _GNU_SOURCE
00035 #define _GNU_SOURCE
00036 #endif
00037
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <fcntl.h>
00044 #include <sys/ioctl.h>
00045 #include <linux/cdrom.h>
00046 #include <errno.h>
00047 #include <string.h>
00048 #include <mntent.h>
00049 #include <sys/wait.h>
00050 #include <sys/utsname.h>
00051 #include <scsi/scsi.h>
00052 #include <scsi/sg.h>
00053 #include <poll.h>
00054 #include <sys/time.h>
00055
00056 #include "linux/linux_dvd_rw_utils.h"
00057
00058 typedef enum {
00059 NONE = CGC_DATA_NONE,
00060 READ = CGC_DATA_READ,
00061 WRITE = CGC_DATA_WRITE
00062 } Direction;
00063
00064 typedef struct ScsiCommand ScsiCommand;
00065
00066 struct ScsiCommand {
00067 int fd;
00068 int autoclose;
00069 char *filename;
00070 struct cdrom_generic_command cgc;
00071 union {
00072 struct request_sense s;
00073 unsigned char u[18];
00074 } _sense;
00075 struct sg_io_hdr sg_io;
00076 };
00077
00078 #define DIRECTION(i) (Dir_xlate[i]);
00079
00080
00081
00082
00083
00084 const int Dir_xlate[4] = {
00085 0,
00086 SG_DXFER_TO_DEV,
00087 SG_DXFER_FROM_DEV,
00088 SG_DXFER_NONE
00089 };
00090
00091 static ScsiCommand *
00092 scsi_command_new (void)
00093 {
00094 ScsiCommand *cmd;
00095
00096 cmd = (ScsiCommand *) malloc (sizeof (ScsiCommand));
00097 memset (cmd, 0, sizeof (ScsiCommand));
00098 cmd->fd = -1;
00099 cmd->filename = NULL;
00100 cmd->autoclose = 1;
00101
00102 return cmd;
00103 }
00104
00105 static ScsiCommand *
00106 scsi_command_new_from_fd (int f)
00107 {
00108 ScsiCommand *cmd;
00109
00110 cmd = scsi_command_new ();
00111 cmd->fd = f;
00112 cmd->autoclose = 0;
00113
00114 return cmd;
00115 }
00116
00117 static void
00118 scsi_command_free (ScsiCommand * cmd)
00119 {
00120 if (cmd->fd >= 0 && cmd->autoclose) {
00121 close (cmd->fd);
00122 cmd->fd = -1;
00123 }
00124 if (cmd->filename) {
00125 free (cmd->filename);
00126 cmd->filename = NULL;
00127 }
00128
00129 free (cmd);
00130 }
00131
00132 static int
00133 scsi_command_transport (ScsiCommand * cmd, Direction dir, void *buf,
00134 size_t sz)
00135 {
00136 int ret = 0;
00137
00138 cmd->sg_io.dxferp = buf;
00139 cmd->sg_io.dxfer_len = sz;
00140 cmd->sg_io.dxfer_direction = DIRECTION (dir);
00141
00142 if (ioctl (cmd->fd, SG_IO, &cmd->sg_io))
00143 return -1;
00144
00145 if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
00146 errno = EIO;
00147 ret = -1;
00148 if (cmd->sg_io.masked_status & CHECK_CONDITION) {
00149 CREAM_ON_ERRNO (cmd->sg_io.sbp);
00150 ret = ERRCODE (cmd->sg_io.sbp);
00151 if (ret == 0)
00152 ret = -1;
00153 }
00154 }
00155
00156 return ret;
00157 }
00158
00159 static void
00160 scsi_command_init (ScsiCommand * cmd, size_t i, int arg)
00161 {
00162 if (i == 0) {
00163 memset (&cmd->cgc, 0, sizeof (cmd->cgc));
00164 memset (&cmd->_sense, 0, sizeof (cmd->_sense));
00165 cmd->cgc.quiet = 1;
00166 cmd->cgc.sense = &cmd->_sense.s;
00167 memset (&cmd->sg_io, 0, sizeof (cmd->sg_io));
00168 cmd->sg_io.interface_id = 'S';
00169 cmd->sg_io.mx_sb_len = sizeof (cmd->_sense);
00170 cmd->sg_io.cmdp = cmd->cgc.cmd;
00171 cmd->sg_io.sbp = cmd->_sense.u;
00172 cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
00173 }
00174 cmd->sg_io.cmd_len = i + 1;
00175 cmd->cgc.cmd[i] = arg;
00176 }
00177
00178 int
00179 get_dvd_r_rw_profile (int fd)
00180 {
00181 ScsiCommand *cmd;
00182 int retval = -1;
00183 unsigned char page[20];
00184 unsigned char *list;
00185 int i, len;
00186
00187 cmd = scsi_command_new_from_fd (fd);
00188
00189 scsi_command_init (cmd, 0, 0x46);
00190 scsi_command_init (cmd, 1, 2);
00191 scsi_command_init (cmd, 8, 8);
00192 scsi_command_init (cmd, 9, 0);
00193 if (scsi_command_transport (cmd, READ, page, 8)) {
00194
00195 scsi_command_free (cmd);
00196 return -1;
00197 }
00198
00199
00200 len = 4 + (page[0] << 24 | page[1] << 16 | page[2] << 8 | page[3]);
00201 if (len > 264) {
00202 scsi_command_free (cmd);
00203
00204 return -1;
00205 }
00206
00207 list = (unsigned char *) malloc (len);
00208
00209 scsi_command_init (cmd, 0, 0x46);
00210 scsi_command_init (cmd, 1, 2);
00211 scsi_command_init (cmd, 7, len >> 8);
00212 scsi_command_init (cmd, 8, len);
00213 scsi_command_init (cmd, 9, 0);
00214 if (scsi_command_transport (cmd, READ, list, len)) {
00215
00216 scsi_command_free (cmd);
00217 free (list);
00218 return -1;
00219 }
00220
00221 for (i = 12; i < list[11]; i += 4) {
00222 int profile = (list[i] << 8 | list[i + 1]);
00223
00224
00225 if (profile == 0x1B) {
00226 if (retval == 1)
00227 retval = 2;
00228 else
00229 retval = 0;
00230 } else if (profile == 0x1A) {
00231 if (retval == 0)
00232 retval = 2;
00233 else
00234 retval = 1;
00235 }
00236 }
00237
00238 scsi_command_free (cmd);
00239 free (list);
00240
00241 return retval;
00242 }
00243
00244 static unsigned char *
00245 pull_page2a_from_fd (int fd)
00246 {
00247 ScsiCommand *cmd;
00248 unsigned char header[12], *page2A;
00249 unsigned int len, bdlen;
00250
00251 cmd = scsi_command_new_from_fd (fd);
00252
00253 scsi_command_init (cmd, 0, 0x5A);
00254 scsi_command_init (cmd, 1, 0x08);
00255 scsi_command_init (cmd, 2, 0x2A);
00256 scsi_command_init (cmd, 8, sizeof (header));
00257 scsi_command_init (cmd, 9, 0);
00258
00259 if (scsi_command_transport (cmd, READ, header, sizeof (header))) {
00260
00261 scsi_command_free (cmd);
00262 return NULL;
00263 }
00264
00265 len = (header[0] << 8 | header[1]) + 2;
00266 bdlen = header[6] << 8 | header[7];
00267
00268
00269 if (bdlen) {
00270 if (len < (8 + bdlen + 30)) {
00271
00272 scsi_command_free (cmd);
00273 return NULL;
00274 }
00275 } else if (len < (8 + 2 + (unsigned int) header[9])) {
00276
00277 len = 8 + 2 + header[9];
00278 }
00279
00280 page2A = (unsigned char *) malloc (len);
00281 if (page2A == NULL) {
00282
00283 scsi_command_free (cmd);
00284 return NULL;
00285 }
00286
00287 scsi_command_init (cmd, 0, 0x5A);
00288 scsi_command_init (cmd, 1, 0x08);
00289 scsi_command_init (cmd, 2, 0x2A);
00290 scsi_command_init (cmd, 7, len >> 8);
00291 scsi_command_init (cmd, 8, len);
00292 scsi_command_init (cmd, 9, 0);
00293 if (scsi_command_transport (cmd, READ, page2A, len)) {
00294
00295 scsi_command_free (cmd);
00296 free (page2A);
00297 return NULL;
00298 }
00299
00300 scsi_command_free (cmd);
00301
00302 len -= 2;
00303
00304 if (len < ((unsigned int) page2A[0] << 8 | page2A[1])) {
00305 page2A[0] = len >> 8;
00306 page2A[1] = len;
00307 }
00308
00309 return page2A;
00310 }
00311
00312 int
00313 get_read_write_speed (int fd, int *read_speed, int *write_speed)
00314 {
00315 unsigned char *page2A;
00316 int len, hlen;
00317 unsigned char *p;
00318
00319 *read_speed = 0;
00320 *write_speed = 0;
00321
00322 page2A = pull_page2a_from_fd (fd);
00323 if (page2A == NULL) {
00324 printf ("Failed to get Page 2A\n");
00325
00326 return -1;
00327 }
00328
00329 len = (page2A[0] << 8 | page2A[1]) + 2;
00330 hlen = 8 + (page2A[6] << 8 | page2A[7]);
00331 p = page2A + hlen;
00332
00333
00334
00335 if (len < (hlen + 30) || p[1] < (30 - 2)) {
00336
00337
00338 if (len < (hlen + 20) || p[1] < (20 - 2))
00339 *write_speed = 0;
00340 else
00341 *write_speed = p[18] << 8 | p[19];
00342 } else {
00343 *write_speed = p[28] << 8 | p[29];
00344 }
00345
00346 *read_speed = p[8] << 8 | p[9];
00347
00348 free (page2A);
00349
00350 return 0;
00351 }