"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/read.c" (30 Jan 2021, 19860 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "read.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
    2 
    3 /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
    4    Copyright (c) 2006 - 2014 Thomas Schmitt <scdbackup@gmx.net>
    5    Provided under GPL version 2 or later.
    6 */
    7 
    8 #ifdef HAVE_CONFIG_H
    9 #include "../config.h"
   10 #endif
   11 
   12 #include <stdlib.h>
   13 #include <unistd.h>
   14 #include <signal.h>
   15 
   16 /* ts A61007 */
   17 /* #include <a ssert.h> */
   18 
   19 #include <stdio.h>
   20 #include <string.h>
   21 #include <ctype.h>
   22 #include <fcntl.h>
   23 #include <errno.h>
   24 
   25 /* ts B41126 : O_BINARY is needed for Cygwin but undefined elsewhere */
   26 #ifndef O_BINARY
   27 #define O_BINARY 0
   28 #endif
   29 
   30 #include "sector.h"
   31 #include "libburn.h"
   32 #include "drive.h"
   33 #include "transport.h"
   34 
   35 /* ts A60925 : obsoleted by libdax_msgs.h
   36 #include "message.h"
   37 */
   38 
   39 #include "crc.h"
   40 #include "debug.h"
   41 #include "init.h"
   42 #include "toc.h"
   43 #include "util.h"
   44 #include "mmc.h"
   45 #include "sg.h"
   46 #include "read.h"
   47 #include "options.h"
   48 
   49 /* ts A70812 */
   50 #include "error.h"
   51 #include "libdax_msgs.h"
   52 extern struct libdax_msgs *libdax_messenger;
   53 
   54 
   55 void burn_disc_read(struct burn_drive *d, const struct burn_read_opts *o)
   56 {
   57 #if 0
   58     int i, end, maxsects, finish;
   59     int seclen;
   60     int drive_lba;
   61     unsigned short crc;
   62     unsigned char fakesub[96];
   63     struct buffer page;  <- needs to become dynamic memory
   64     int speed;
   65 
   66     /* ts A61007 : if this function gets revived, then these
   67             tests have to be done more graceful */
   68     a ssert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
   69     a ssert(!d->busy);
   70     a ssert(d->toc->valid);
   71     a ssert(o->datafd != -1);
   72 
   73     /* moved up from spc_select_error_params alias d->send_parameters() */
   74     a ssert(d->mdata->valid);
   75 
   76 /* XXX not sure this is a good idea.  copy it? */
   77 /* XXX also, we have duplicated data now, do we remove the fds from struct 
   78 drive, or only store a subset of the _opts structs in drives */
   79 
   80     /* set the speed on the drive */
   81     speed = o->speed > 0 ? o->speed : d->mdata->max_read_speed;
   82     d->set_speed(d, speed, 0);
   83 
   84     d->params.retries = o->hardware_error_retries;
   85 
   86     d->send_parameters(d, o);
   87 
   88     d->cancel = 0;
   89     d->busy = BURN_DRIVE_READING;
   90     d->currsession = 0;
   91 /*  drive_lba = 232000;
   92     d->currtrack = 18;
   93 */
   94     d->currtrack = 0;
   95     drive_lba = 0;
   96 /* XXX removal of this line obviously breaks *
   97    d->track_end = burn_track_end(d, d->currsession, d->currtrack);*/
   98     printf("track ends at %d\n", d->track_end);
   99     page.sectors = 0;
  100     page.bytes = 0;
  101 
  102     if (o->subfd != -1) {
  103         memset(fakesub, 0xFF, 12);
  104         memset(fakesub + 12, 0, 84);
  105         fakesub[13] = 1;
  106         fakesub[14] = 1;
  107         fakesub[20] = 2;
  108         fakesub[12] = (d->toc->toc_entry[0].control << 4) +
  109             d->toc->toc_entry[0].adr;
  110 
  111 #ifdef Libburn_no_crc_C
  112         crc = 0; /* dummy */
  113 #else
  114         crc = crc_ccitt(fakesub + 12, 10);
  115 #endif
  116 
  117         fakesub[22] = crc >> 8;
  118         fakesub[23] = crc & 0xFF;
  119         write(o->subfd, fakesub, 96);
  120     }
  121     while (1) {
  122         seclen = burn_sector_length_read(d, o);
  123 
  124         for (i = 0; i < page.sectors; i++) {
  125             burn_packet_process(d, page.data + seclen * i, o);
  126             d->track_end--;
  127             drive_lba++;
  128         }
  129 
  130         if ((d->cancel) || (drive_lba == LAST_SESSION_END(d))) {
  131             d->busy = BURN_DRIVE_IDLE;
  132             if (!d->cancel)
  133                 d->toc->complete = 1;
  134             return;
  135         }
  136 /* XXX: removal of this line obviously breaks *
  137         end = burn_track_end(d, d->currsession, d->currtrack); */
  138 
  139         if (drive_lba == end) {
  140             d->currtrack++;
  141             if (d->currtrack >
  142                 d->toc->session[d->currsession].lasttrack) {
  143                 d->currsession++;
  144                 /* session switch to d->currsession */
  145                 /* skipping a lead out */
  146                 drive_lba = CURRENT_SESSION_START(d);
  147 /* XXX more of the same
  148                 end = burn_track_end(d, d->currsession,
  149                             d->currtrack);
  150 */
  151             }
  152         }
  153 
  154         page.sectors = 0;
  155         page.bytes = 0;
  156 
  157         maxsects = BUFFER_SIZE / seclen;
  158         finish = end - drive_lba;
  159 
  160         d->track_end = finish;
  161 
  162         page.sectors = (finish < maxsects) ? finish : maxsects;
  163         printf("reading %d sectors from %d\n", page.sectors,
  164                drive_lba);
  165 
  166         /* >>> ts A61009 : ensure page.sectors >= 0 before calling */
  167         /* >>> ts B21123 :  Would now be d->read_cd() with
  168                                     with sectype = 0 , mainch = 0xf8 */
  169         d->r ead_sectors(d, drive_lba, page.sectors, o, &page);
  170 
  171         printf("Read %d\n", page.sectors);
  172     }
  173 #endif
  174 }
  175 int burn_sector_length_read(struct burn_drive *d,
  176                 const struct burn_read_opts *o)
  177 {
  178     int dlen = 2352;
  179     int data;
  180 
  181 /*XXX how do we handle this crap now?*/
  182 /*  data = d->toc->track[d->currtrack].toc_entry->control & 4;*/
  183     data = 1;
  184     if (o->report_recovered_errors)
  185         dlen += 294;
  186     if ((o->subcodes_data) && data)
  187         dlen += 96;
  188     if ((o->subcodes_audio) && !data)
  189         dlen += 96;
  190     return dlen;
  191 }
  192 
  193 static int bitcount(unsigned char *data, int n)
  194 {
  195     int i, j, count = 0;
  196     unsigned char tem;
  197 
  198     for (i = 0; i < n; i++) {
  199         tem = data[i];
  200         for (j = 0; j < 8; j++) {
  201             count += tem & 1;
  202             tem >>= 1;
  203         }
  204     }
  205     return count;
  206 }
  207 
  208 
  209 void burn_packet_process(struct burn_drive *d, unsigned char *data,
  210              const struct burn_read_opts *o)
  211 {
  212     unsigned char sub[96];
  213     int ptr = 2352, i, j, code, fb;
  214     int audio = 1;
  215 #ifndef Libburn_no_crc_C
  216     unsigned short crc;
  217 #endif
  218 
  219     if (o->c2errors) {
  220         fb = bitcount(data + ptr, 294);
  221         if (fb) {
  222             /* bitcount(data + ptr, 294) damaged bits */;
  223         }
  224         ptr += 294;
  225     }
  226 /*
  227     if (d->toc->track[d->currtrack].mode == BURN_MODE_UNINITIALIZED) {
  228         if ((d->toc->track[d->currtrack].toc_entry->control & 4) == 0)
  229             d->toc->track[d->currtrack].mode = BURN_MODE_AUDIO;
  230         else
  231             switch (data[15]) {
  232             case 0:
  233                 d->toc->track[d->currtrack].mode = BURN_MODE0;
  234                 break;
  235             case 1:
  236                 d->toc->track[d->currtrack].mode = BURN_MODE1;
  237                 break;
  238             case 2:
  239                 d->toc->track[d->currtrack].mode =
  240                     BURN_MODE2_FORMLESS;
  241                 break;
  242             }
  243     }
  244 */
  245     if ((audio && o->subcodes_audio)
  246         || (!audio && o->subcodes_data)) {
  247         memset(sub, 0, sizeof(sub));
  248         for (i = 0; i < 12; i++) {
  249             for (j = 0; j < 8; j++) {
  250                 for (code = 0; code < 8; code++) {
  251                     sub[code * 12 + i] <<= 1;
  252                     if (data[ptr + j + i * 8] &
  253                         (1 << (7 - code)))
  254                         sub[code * 12 + i]++;
  255                 }
  256             }
  257         }
  258 
  259 #ifndef Libburn_no_crc_C
  260         crc = (*(sub + 22) << 8) + *(sub + 23);
  261         if (crc != crc_ccitt(sub + 12, 10)) {
  262 /*
  263             burn_print(1, "sending error on %s %s\n",
  264                    d->idata->vendor, d->idata->product);
  265             e = burn_error();
  266             e->drive = d;
  267             burn_print(1, "crc mismatch in Q\n");
  268 */;
  269         }
  270 #endif
  271 
  272         /* else process_q(d, sub + 12); */
  273         /* 
  274            if (o->subfd != -1) write(o->subfd, sub, 96); */
  275     }
  276 /*
  277     if ((d->track_end <= 150)
  278         && (drive_lba + 150 < CURRENT_SESSION_END(d))
  279         && (TOC_ENTRY(d->toc, d->currtrack).control == 4)
  280         && (TOC_ENTRY(d->toc, d->currtrack + 1).control == 0)) {
  281         burn_print(12, "pregap : %d\n", d->track_end);
  282         write(o->binfd, zeros, 2352);
  283 
  284 #warning XXX WHERE ARE MY SUBCODES
  285                 } else
  286 *//* write(o->datafd, data, 2352); */
  287 }
  288 
  289 /*  so yeah, when you uncomment these, make them write zeros instead of crap
  290 static void write_empty_sector(int fd)
  291 {
  292     static char sec[2352], initialized = 0;
  293 
  294     if (!initialized) {
  295         memset(sec, 0, 2352);
  296         initialized = 1;
  297     }
  298     burn_print(1, "writing an 'empty' sector\n");
  299     write(fd, sec, 2352);
  300 }
  301 
  302 static void write_empty_subcode(int fd)
  303 {
  304     char sub[96];
  305 
  306     write(fd, sub, 96);
  307 }
  308 
  309 static void flipq(unsigned char *sub)
  310 {
  311     *(sub + 12 + 10) = ~*(sub + 12 + 10);
  312     *(sub + 12 + 11) = ~*(sub + 12 + 11);
  313 }
  314 */
  315 
  316 
  317 /** @param flag bit1= be silent on failure
  318                 bit5= report failure with severity DEBUG
  319 */
  320 static int burn_stdio_seek(int fd, off_t byte_address, struct burn_drive *d,
  321                            int flag)
  322 {
  323     char msg[80];
  324 
  325     if (lseek(fd, byte_address, SEEK_SET) != -1)
  326         return 1;
  327     if (!(flag & 2)) {
  328         sprintf(msg, "Cannot address start byte %.f",
  329                 (double) byte_address);
  330                 libdax_msgs_submit(libdax_messenger,
  331                 d->global_index, 0x00020147,
  332                 (flag & 32) ?
  333                  LIBDAX_MSGS_SEV_DEBUG : LIBDAX_MSGS_SEV_SORRY,
  334                 LIBDAX_MSGS_PRIO_HIGH, msg, errno, 0);
  335     }
  336     return 0;
  337 }
  338 
  339 
  340 /* ts A70904 */
  341 /** @param flag bit0= be silent on data shortage
  342                 bit5= report data shortage with severity DEBUG
  343 */
  344 int burn_stdio_read(int fd, char *buf, int bufsize, struct burn_drive *d,
  345             int flag)
  346 {
  347     int todo, count = 0;
  348 
  349     for(todo = bufsize; todo > 0; ) {
  350         count = read(fd, buf + (bufsize - todo), todo);
  351         if(count <= 0)
  352     break;
  353         todo -= count;
  354     }
  355     if(todo > 0 && !(flag & 1)) {
  356         libdax_msgs_submit(libdax_messenger, d->global_index,
  357             0x0002014a,
  358             (flag & 32) ?
  359               LIBDAX_MSGS_SEV_DEBUG : LIBDAX_MSGS_SEV_SORRY,
  360              LIBDAX_MSGS_PRIO_HIGH,
  361             "Cannot read desired amount of data", errno, 0);
  362     }
  363     if (count < 0)
  364         return -1;
  365     return (bufsize - todo);
  366 }
  367 
  368 
  369 /* With DVD and BD media, the minimum ECC entity is read instead of single
  370    blocks.
  371    @param flag see burn_read_data() in libburn.h
  372 */
  373 static int retry_mmc_read(struct burn_drive *d, int chunksize, int sose_mem,
  374                           int start, char **wpt, off_t *data_count,
  375                           int flag)
  376 {
  377     int i, err, todo;
  378     int retry_at, retry_size;
  379 
  380     retry_at = start;
  381     retry_size = chunksize;
  382     todo = chunksize;
  383     retry_size = 16;                               /* DVD ECC block size */
  384     if (d->current_is_cd_profile) {
  385         retry_size = 1;                             /* CD block size */
  386     } else if (d->current_profile >= 0x40 && d->current_profile <= 0x43) {
  387         retry_size = 32;                          /* BD cluster size */
  388     }
  389     for (i = 0; todo > 0; i++) {
  390         if (flag & 2)
  391             d->silent_on_scsi_error = 1;
  392         else if (flag & 32)
  393             d->silent_on_scsi_error = 3;
  394         retry_at = start + i * retry_size;
  395         if (retry_size > todo)
  396             retry_size = todo;
  397         err = d->read_10(d, retry_at, retry_size, d->buffer);
  398         if (flag & (2 | 32)) 
  399             d->silent_on_scsi_error = sose_mem;
  400         if (err == BE_CANCELLED)
  401             return 0;
  402         memcpy(*wpt, d->buffer->data, retry_size * 2048);
  403         *wpt += retry_size * 2048;
  404         *data_count += retry_size * 2048;
  405         todo -= retry_size;
  406     }
  407     return 1;
  408 }
  409 
  410 
  411 /* @param flag see burn_read_data() in libburn.h
  412 */
  413 static int retry_stdio_read(struct burn_drive *d, int fd, int chunksize,
  414                             int start, char **wpt, off_t *data_count,
  415                             int flag)
  416 {
  417     int i, ret, to_read, todo;
  418 
  419     ret = burn_stdio_seek(fd, ((off_t) start) * 2048, d, flag & 2);
  420     if (ret <= 0)
  421         return ret;
  422     todo = chunksize * 2048;
  423     for (i = 0; todo > 0; i += 2048) {
  424         to_read = todo;
  425         if (to_read > 2048)
  426             to_read = 2048;
  427         ret = burn_stdio_read(fd, (char *) d->buffer->data, to_read,
  428                     d, 1);
  429         if (ret <= 0)
  430             return 0;
  431         memcpy(*wpt, d->buffer->data, to_read);
  432         *wpt += to_read;
  433         *data_count += to_read;
  434         todo -= to_read;
  435     }
  436     return 1;
  437 }
  438 
  439 
  440 /* ts A70812 : API function */
  441 int burn_read_data(struct burn_drive *d, off_t byte_address,
  442                    char data[], off_t data_size, off_t *data_count, int flag)
  443 {
  444     int alignment = 2048, start, upto, chunksize = 1, err, cpy_size;
  445     int sose_mem = 0, fd = -1, ret;
  446     char msg[81], *wpt;
  447     struct buffer *buf = NULL, *buffer_mem = d->buffer;
  448 
  449 /*
  450 #define Libburn_read_data_adr_logginG 1
  451 */
  452 #ifdef Libburn_read_data_adr_logginG
  453     static FILE *log_fp= NULL;
  454 
  455     if(log_fp == NULL)
  456         log_fp = fopen("/tmp/burn_read_data_log", "a");
  457     if(log_fp!=NULL)
  458         fprintf(log_fp, "%d\n", (int) (byte_address / 2048));
  459 #endif /* Libburn_read_data_logginG */
  460 
  461     BURN_ALLOC_MEM(buf, struct buffer, 1);
  462     *data_count = 0;
  463     sose_mem = d->silent_on_scsi_error;
  464 
  465     if (d->released) {
  466         libdax_msgs_submit(libdax_messenger,
  467             d->global_index, 0x00020142,
  468             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  469             "Drive is not grabbed on random access read", 0, 0);
  470         {ret = 0; goto ex;}
  471     }
  472     if (d->drive_role == 0) {
  473         libdax_msgs_submit(libdax_messenger, d->global_index,
  474             0x00020146,
  475             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  476             "Drive is a virtual placeholder (null-drive)", 0, 0);
  477         {ret = 0; goto ex;}
  478     } else if (d->drive_role == 3) {
  479         libdax_msgs_submit(libdax_messenger, d->global_index,
  480             0x00020151,
  481             LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
  482             "Read attempt on write-only drive", 0, 0);
  483         {ret = 0; goto ex;}
  484     }
  485     if ((byte_address % alignment) != 0) {
  486         sprintf(msg,
  487             "Read start address not properly aligned (%d bytes)",
  488             alignment);
  489         libdax_msgs_submit(libdax_messenger, d->global_index,
  490             0x00020143,
  491             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  492             msg, 0, 0);
  493         {ret = 0; goto ex;}
  494     }
  495     if (d->media_read_capacity != 0x7fffffff && byte_address >=
  496         ((off_t) d->media_read_capacity + (off_t) 1) * (off_t) 2048) {
  497         if (!(flag & 2)) {
  498             sprintf(msg,
  499               "Read start address %ds larger than number of readable blocks %d",
  500               (int) (byte_address / 2048 + !!(byte_address % 2048)),
  501               d->media_read_capacity + 1);
  502             libdax_msgs_submit(libdax_messenger, d->global_index,
  503                 0x00020172, (flag & 32) ?
  504                 LIBDAX_MSGS_SEV_DEBUG : LIBDAX_MSGS_SEV_SORRY,
  505                 LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
  506         }
  507         {ret = 0; goto ex;}
  508     }
  509 
  510     if (d->busy != BURN_DRIVE_IDLE) {
  511         libdax_msgs_submit(libdax_messenger,
  512             d->global_index, 0x00020145,
  513             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  514             "Drive is busy on attempt to read data", 0, 0);
  515         {ret = 0; goto ex;}
  516     }
  517 
  518     if (d->drive_role != 1) {
  519 
  520 /* <<< We need _LARGEFILE64_SOURCE defined by the build system.
  521 */
  522 #ifndef O_LARGEFILE
  523 #define O_LARGEFILE 0
  524 #endif
  525 
  526         fd = d->stdio_fd;
  527         if (fd < 0)
  528             d->stdio_fd = fd =
  529                 open(d->devname,
  530                      O_RDONLY | O_LARGEFILE | O_BINARY);
  531         if (fd == -1) {
  532             if (errno == EACCES && (flag & 2)) {
  533                 if (!(flag & 8))
  534                     libdax_msgs_submit(libdax_messenger,
  535                       d->global_index, 0x00020183,
  536                       LIBDAX_MSGS_SEV_WARNING,
  537                       LIBDAX_MSGS_PRIO_HIGH,
  538               "Failed to open device (a pseudo-drive) for reading",
  539                       errno, 0);
  540             } else if (errno != ENOENT || !(flag & 2))
  541                 libdax_msgs_submit(libdax_messenger,
  542                     d->global_index, 0x00020005,
  543                     (flag & 32) && errno == ENOENT ?
  544                         LIBDAX_MSGS_SEV_DEBUG :
  545                         LIBDAX_MSGS_SEV_SORRY,
  546                     LIBDAX_MSGS_PRIO_HIGH,
  547               "Failed to open device (a pseudo-drive) for reading",
  548                     errno, 0);
  549             ret = 0;
  550             if (errno == EACCES && (flag & 8))
  551                 ret= -2;
  552             goto ex;
  553         }
  554         ret = burn_stdio_seek(fd, byte_address, d, flag & (2 | 32));
  555         if (ret <= 0)
  556             goto ex;
  557     }
  558 
  559     d->busy = BURN_DRIVE_READING_SYNC;
  560     d->buffer = buf;
  561 
  562     start = byte_address / 2048;
  563     upto = start + data_size / 2048;
  564     if (data_size % 2048)
  565         upto++;
  566     wpt = data;
  567     for (; start < upto; start += chunksize) {
  568         chunksize = upto - start;
  569         if (chunksize > (BUFFER_SIZE / 2048)) {
  570             chunksize = (BUFFER_SIZE / 2048);
  571             cpy_size = BUFFER_SIZE;
  572         } else
  573             cpy_size = data_size - *data_count;
  574         if (flag & 2)
  575             d->silent_on_scsi_error = 1;
  576         else if (flag & 32)
  577             d->silent_on_scsi_error = 3;
  578         if (flag & 16) {
  579             d->had_particular_error &= ~1;
  580             if (!d->silent_on_scsi_error)
  581                 d->silent_on_scsi_error = 2;
  582         }
  583         if (d->drive_role == 1) {
  584             err = d->read_10(d, start, chunksize, d->buffer);
  585         } else {
  586             ret = burn_stdio_read(fd, (char *) d->buffer->data,
  587                           cpy_size, d,
  588                           (flag & 32) | !!(flag & 2));
  589             err = 0;
  590             if (ret <= 0)
  591                 err = BE_CANCELLED;
  592         }
  593         if (flag & (2 | 16 | 32))
  594             d->silent_on_scsi_error = sose_mem;
  595         if (err == BE_CANCELLED) {
  596             if ((flag & 16) && (d->had_particular_error & 1))
  597                 {ret = -3; goto ex;}
  598             /* Retry: with CD read by single blocks
  599                       with other media: retry in full chunks
  600             */
  601             if(flag & 4)
  602                 goto bad_read;
  603             if (d->drive_role == 1) {
  604                 ret = retry_mmc_read(d, chunksize, sose_mem,
  605                         start, &wpt, data_count, flag);
  606             } else {
  607                 ret = retry_stdio_read(d, fd, chunksize, 
  608                         start, &wpt, data_count, flag);
  609             }
  610             if (ret <= 0)
  611                 goto bad_read;
  612         } else {
  613             memcpy(wpt, d->buffer->data, cpy_size);
  614             wpt += cpy_size;
  615             *data_count += cpy_size;
  616         }
  617     }
  618 
  619     ret = 1;
  620 ex:;
  621     BURN_FREE_MEM(buf);
  622     d->buffer = buffer_mem;
  623     d->busy = BURN_DRIVE_IDLE;
  624     return ret;
  625 
  626 bad_read:;
  627     if (!(flag & 2))
  628         libdax_msgs_submit(libdax_messenger, d->global_index,
  629                 0x00020000,
  630                 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  631                 "burn_read_data() returns 0", 0, 0);
  632     ret = 0; goto ex;
  633 }
  634 
  635 
  636 /* ts B21119 : API function*/
  637 int burn_read_audio(struct burn_drive *d, int sector_no,
  638                     char data[], off_t data_size, off_t *data_count, int flag)
  639 {
  640     int alignment = 2352, start, upto, chunksize = 1, err, cpy_size, i;
  641     int sose_mem = 0, ret;
  642     char msg[81], *wpt;
  643     struct buffer *buf = NULL, *buffer_mem = d->buffer;
  644 
  645     BURN_ALLOC_MEM(buf, struct buffer, 1);
  646     *data_count = 0;
  647     sose_mem = d->silent_on_scsi_error;
  648 
  649     if (d->released) {
  650         libdax_msgs_submit(libdax_messenger,
  651             d->global_index, 0x00020142,
  652             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  653             "Drive is not grabbed on random access read", 0, 0);
  654         {ret = 0; goto ex;}
  655     }
  656     if (d->drive_role != 1) {
  657         libdax_msgs_submit(libdax_messenger, d->global_index,
  658             0x00020146,
  659             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  660         "Drive is a virtual placeholder (stdio-drive or null-drive)",
  661              0, 0);
  662         {ret = 0; goto ex;} 
  663     }
  664     if ((data_size % alignment) != 0) {
  665         sprintf(msg,
  666             "Audio read size not properly aligned (%d bytes)",
  667             alignment);
  668         libdax_msgs_submit(libdax_messenger, d->global_index,
  669             0x0002019d,
  670             LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  671             msg, 0, 0);
  672         {ret = 0; goto ex;}
  673     }
  674     if (d->busy != BURN_DRIVE_IDLE) {
  675         libdax_msgs_submit(libdax_messenger,
  676             d->global_index, 0x00020145,
  677             LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  678             "Drive is busy on attempt to read audio", 0, 0);
  679         {ret = 0; goto ex;}
  680     }
  681 
  682         d->busy = BURN_DRIVE_READING_SYNC;
  683         d->buffer = buf;
  684 
  685     start = sector_no;
  686     upto = start + data_size / alignment;
  687     wpt = data;
  688     for (; start < upto; start += chunksize) {
  689         chunksize = upto - start;
  690         if (chunksize > (BUFFER_SIZE / alignment))
  691             chunksize = (BUFFER_SIZE / alignment);
  692         cpy_size = chunksize * alignment;
  693         if (flag & 2)
  694             d->silent_on_scsi_error = 1;
  695         else if (flag & 32)
  696             d->silent_on_scsi_error = 3;
  697         if (flag & 16) {
  698             d->had_particular_error &= ~1;
  699             if (!d->silent_on_scsi_error)
  700                 d->silent_on_scsi_error = 2;
  701         }
  702         err = d->read_cd(d, start, chunksize, 1, 0x10, NULL, d->buffer,
  703                  (flag & 8) >> 3);
  704         if (flag & (2 | 16 | 32))
  705             d->silent_on_scsi_error = sose_mem;
  706         if (err == BE_CANCELLED) {
  707             if ((flag & 16) && (d->had_particular_error & 1))
  708                 {ret = -3; goto ex;}
  709             if(!(flag & 4))
  710               for (i = 0; i < chunksize - 1; i++) {
  711                 if (flag & 2)
  712                     d->silent_on_scsi_error = 1;
  713                 else if (flag & 32)
  714                     d->silent_on_scsi_error = 3;
  715                 err = d->read_cd(d, start + i, 1, 1, 0x10,
  716                              NULL, d->buffer, (flag & 8) >> 3);
  717                 if (flag & (2 | 32))
  718                     d->silent_on_scsi_error = sose_mem;
  719                 if (err == BE_CANCELLED)
  720               break;
  721                 memcpy(wpt, d->buffer->data, alignment);
  722                 wpt += alignment;
  723                 *data_count += alignment;
  724               }
  725 
  726             ret = 0; goto ex;
  727         }
  728                 memcpy(wpt, d->buffer->data, cpy_size);
  729                 wpt += cpy_size;
  730                 *data_count += cpy_size;
  731         }
  732 
  733     ret = 1;
  734 ex:
  735     BURN_FREE_MEM(buf);
  736     d->buffer = buffer_mem;
  737     d->busy = BURN_DRIVE_IDLE;
  738     return ret;
  739 }
  740 
  741 
  742 #ifdef Libburn_develop_quality_scaN
  743 
  744 /* B21108 ts */
  745 int burn_nec_optiarc_rep_err_rate(struct burn_drive *d,
  746                                   int start_lba, int rate_period, int flag)
  747 {
  748     int ret, lba = 0, error_rate1 = 0, error_rate2 = 0, enabled = 0, dret;
  749 
  750     /* Sub Operation Code 1 : Enable Error Rate reporting function */
  751     ret = mmc_nec_optiarc_f3(d, 1, start_lba, rate_period,
  752                              &lba, &error_rate1, &error_rate2);
  753     if (ret <= 0)
  754         goto ex;
  755     enabled = 1;
  756 
  757     /* >>> Sub Operation Code 2 : Seek to starting address
  758                start_lba , rate_period
  759     */;
  760 
  761     /* >>> Loop with Sub Operation Code 3 : Send Error Rate information
  762                reply: 4-byte LBA , 2-byte C1/PIE , 2-byte C2/PIF
  763     */;
  764 
  765     ret = 1;
  766 ex:;
  767     if (enabled) {
  768         /* Code F : Disable Error Rate reporting function */
  769         dret = mmc_nec_optiarc_f3(d, 0xf, 0, 0,
  770                     &lba, &error_rate1, &error_rate2);
  771         if (dret < ret)
  772             ret = dret;
  773     }
  774     return ret;
  775 }
  776 
  777 #endif /* Libburn_develop_quality_scaN */
  778