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 {
00122 close (cmd->fd);
00123 cmd->fd = -1;
00124 }
00125 if (cmd->filename)
00126 {
00127 free (cmd->filename);
00128 cmd->filename = NULL;
00129 }
00130
00131 free (cmd);
00132 }
00133
00134 static int
00135 scsi_command_transport (ScsiCommand *cmd, Direction dir, void *buf, size_t sz)
00136 {
00137 int ret = 0;
00138
00139 cmd->sg_io.dxferp = buf;
00140 cmd->sg_io.dxfer_len = sz;
00141 cmd->sg_io.dxfer_direction = DIRECTION(dir);
00142
00143 if (ioctl (cmd->fd, SG_IO, &cmd->sg_io))
00144 return -1;
00145
00146 if ((cmd->sg_io.info&SG_INFO_OK_MASK) != SG_INFO_OK)
00147 {
00148 errno=EIO;
00149 ret=-1;
00150 if (cmd->sg_io.masked_status & CHECK_CONDITION)
00151 {
00152 CREAM_ON_ERRNO(cmd->sg_io.sbp);
00153 ret=ERRCODE(cmd->sg_io.sbp);
00154 if (ret==0)
00155 ret=-1;
00156 }
00157 }
00158
00159 return ret;
00160 }
00161
00162 static void
00163 scsi_command_init (ScsiCommand *cmd, size_t i, int arg)
00164 {
00165 if (i == 0)
00166 {
00167 memset(&cmd->cgc,0,sizeof(cmd->cgc));
00168 memset(&cmd->_sense,0,sizeof(cmd->_sense));
00169 cmd->cgc.quiet = 1;
00170 cmd->cgc.sense = &cmd->_sense.s;
00171 memset(&cmd->sg_io,0,sizeof(cmd->sg_io));
00172 cmd->sg_io.interface_id= 'S';
00173 cmd->sg_io.mx_sb_len = sizeof(cmd->_sense);
00174 cmd->sg_io.cmdp = cmd->cgc.cmd;
00175 cmd->sg_io.sbp = cmd->_sense.u;
00176 cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT|SG_FLAG_DIRECT_IO;
00177 }
00178 cmd->sg_io.cmd_len = i+1;
00179 cmd->cgc.cmd[i] = arg;
00180 }
00181
00182 int
00183 get_dvd_r_rw_profile (int fd)
00184 {
00185 ScsiCommand *cmd;
00186 int retval = -1;
00187 unsigned char page[20];
00188 unsigned char *list;
00189 int i, len;
00190
00191 cmd = scsi_command_new_from_fd (fd);
00192
00193 scsi_command_init (cmd, 0, 0x46);
00194 scsi_command_init (cmd, 1, 2);
00195 scsi_command_init (cmd, 8, 8);
00196 scsi_command_init (cmd, 9, 0);
00197 if (scsi_command_transport (cmd, READ, page, 8))
00198 {
00199
00200 scsi_command_free (cmd);
00201 return -1;
00202 }
00203
00204
00205 len = 4 + (page[0] << 24 | page[1] << 16 | page[2] << 8 | page[3]);
00206 if (len > 264)
00207 {
00208 scsi_command_free (cmd);
00209
00210 return -1;
00211 }
00212
00213 list = (unsigned char *) malloc (len);
00214
00215 scsi_command_init (cmd, 0, 0x46);
00216 scsi_command_init (cmd, 1, 2);
00217 scsi_command_init (cmd, 7, len >> 8);
00218 scsi_command_init (cmd, 8, len);
00219 scsi_command_init (cmd, 9, 0);
00220 if (scsi_command_transport (cmd, READ, list, len))
00221 {
00222
00223 scsi_command_free (cmd);
00224 free (list);
00225 return -1;
00226 }
00227
00228 for (i = 12 ; i < list[11] ; i += 4)
00229 {
00230 int profile = (list[i] <<8 | list[i+1]);
00231
00232
00233 if (profile == 0x1B)
00234 {
00235 if (retval == 1)
00236 retval = 2;
00237 else
00238 retval = 0;
00239 } else if (profile == 0x1A) {
00240 if (retval == 0)
00241 retval = 2;
00242 else
00243 retval = 1;
00244 }
00245 }
00246
00247 scsi_command_free (cmd);
00248 free (list);
00249
00250 return retval;
00251 }
00252
00253 static unsigned char *
00254 pull_page2a_from_fd (int fd)
00255 {
00256 ScsiCommand *cmd;
00257 unsigned char header[12], *page2A;
00258 unsigned int len, bdlen;
00259
00260 cmd = scsi_command_new_from_fd (fd);
00261
00262 scsi_command_init (cmd, 0, 0x5A);
00263 scsi_command_init (cmd, 1, 0x08);
00264 scsi_command_init (cmd, 2, 0x2A);
00265 scsi_command_init (cmd, 8, sizeof (header));
00266 scsi_command_init (cmd, 9, 0);
00267
00268 if (scsi_command_transport (cmd, READ, header, sizeof (header)))
00269 {
00270
00271 scsi_command_free (cmd);
00272 return NULL;
00273 }
00274
00275 len = (header[0] << 8 | header[1]) + 2;
00276 bdlen = header[6] << 8 | header[7];
00277
00278
00279 if (bdlen)
00280 {
00281 if (len < (8 + bdlen + 30))
00282 {
00283
00284 scsi_command_free (cmd);
00285 return NULL;
00286 }
00287 } else if (len < (8 + 2 + (unsigned int) header[9])) {
00288
00289 len = 8+2+header[9];
00290 }
00291
00292 page2A = (unsigned char *)malloc(len);
00293 if (page2A == NULL)
00294 {
00295
00296 scsi_command_free (cmd);
00297 return NULL;
00298 }
00299
00300 scsi_command_init (cmd, 0, 0x5A);
00301 scsi_command_init (cmd, 1, 0x08);
00302 scsi_command_init (cmd, 2, 0x2A);
00303 scsi_command_init (cmd, 7, len >> 8);
00304 scsi_command_init (cmd, 8, len);
00305 scsi_command_init (cmd, 9, 0);
00306 if (scsi_command_transport (cmd, READ, page2A, len))
00307 {
00308
00309 scsi_command_free (cmd);
00310 free (page2A);
00311 return NULL;
00312 }
00313
00314 scsi_command_free (cmd);
00315
00316 len -= 2;
00317
00318 if (len < ((unsigned int) page2A[0] << 8 | page2A[1]))
00319 {
00320 page2A[0] = len >> 8;
00321 page2A[1] = len;
00322 }
00323
00324 return page2A;
00325 }
00326
00327 int
00328 get_read_write_speed (int fd, int *read_speed, int *write_speed)
00329 {
00330 unsigned char *page2A;
00331 int len, hlen;
00332 unsigned char *p;
00333
00334 *read_speed = 0;
00335 *write_speed =0;
00336
00337 page2A = pull_page2a_from_fd (fd);
00338 if (page2A == NULL)
00339 {
00340 printf ("Failed to get Page 2A\n");
00341
00342 return -1;
00343 }
00344
00345 len = (page2A[0] << 8 | page2A[1]) + 2;
00346 hlen = 8 + (page2A[6] << 8 | page2A[7]);
00347 p = page2A + hlen;
00348
00349
00350
00351 if (len < (hlen + 30) || p[1] < (30 - 2))
00352 {
00353
00354
00355 if (len < (hlen + 20) || p[1] < (20 -2))
00356 *write_speed = 0;
00357 else
00358 *write_speed = p[18] << 8 | p[19];
00359 } else {
00360 *write_speed = p[28] << 8 | p[29];
00361 }
00362
00363 *read_speed = p[8] << 8 | p[9];
00364
00365 free (page2A);
00366
00367 return 0;
00368 }
00369