~ubuntu-branches/ubuntu/edgy/libcdio/edgy-updates

« back to all changes in this revision

Viewing changes to lib/_cdio_linux.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-11-15 16:53:23 UTC
  • mfrom: (3.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20051115165323-peroku75syl2j36u
Tags: 0.76-1ubuntu1
* Sync to new Debian version, manually apply Ubuntu patches:
  - debian/control: Remove dpkg-awk build dependency.
  - debian/rules: hardcode $LIBCDEV. This keeps the diff small (compared to
    the original patch of changing every ${libcdev} occurence).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    $Id: _cdio_linux.c,v 1.99 2004/11/20 12:41:21 rocky Exp $
3
 
 
4
 
    Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
5
 
    Copyright (C) 2002, 2003, 2004 Rocky Bernstein <rocky@panix.com>
6
 
 
7
 
    This program is free software; you can redistribute it and/or modify
8
 
    it under the terms of the GNU General Public License as published by
9
 
    the Free Software Foundation; either version 2 of the License, or
10
 
    (at your option) any later version.
11
 
 
12
 
    This program is distributed in the hope that it will be useful,
13
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
    GNU General Public License for more details.
16
 
 
17
 
    You should have received a copy of the GNU General Public License
18
 
    along with this program; if not, write to the Free Software
19
 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 
*/
21
 
 
22
 
/* This file contains Linux-specific code and implements low-level 
23
 
   control of the CD drive.
24
 
*/
25
 
 
26
 
#ifdef HAVE_CONFIG_H
27
 
# include "config.h"
28
 
#endif
29
 
 
30
 
static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.99 2004/11/20 12:41:21 rocky Exp $";
31
 
 
32
 
#include <string.h>
33
 
 
34
 
#include <cdio/sector.h>
35
 
#include <cdio/util.h>
36
 
#include <cdio/types.h>
37
 
#include <cdio/scsi_mmc.h>
38
 
#include <cdio/cdtext.h>
39
 
#include "cdtext_private.h"
40
 
#include "cdio_assert.h"
41
 
#include "cdio_private.h"
42
 
 
43
 
#ifdef HAVE_LINUX_CDROM
44
 
 
45
 
#if defined(HAVE_LINUX_VERSION_H)
46
 
# include <linux/version.h>
47
 
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
48
 
#   define __CDIO_LINUXCD_BUILD
49
 
# else
50
 
#  error "You need a kernel greater than 2.2.16 to have CDROM support"
51
 
# endif
52
 
#else 
53
 
#  error "You need <linux/version.h> to have CDROM support"
54
 
#endif
55
 
 
56
 
#include <stdio.h>
57
 
#include <stdlib.h>
58
 
#include <errno.h>
59
 
#include <unistd.h>
60
 
#include <fcntl.h>
61
 
#include <mntent.h>
62
 
 
63
 
#include <linux/cdrom.h>
64
 
#include <scsi/scsi.h>
65
 
#include <scsi/sg.h>
66
 
#include <scsi/scsi_ioctl.h>
67
 
#include <sys/mount.h>
68
 
 
69
 
#include <sys/stat.h>
70
 
#include <sys/types.h>
71
 
#include <sys/ioctl.h>
72
 
 
73
 
typedef enum {
74
 
  _AM_NONE,
75
 
  _AM_IOCTL,
76
 
  _AM_READ_CD,
77
 
  _AM_READ_10
78
 
} access_mode_t;
79
 
 
80
 
typedef struct {
81
 
  /* Things common to all drivers like this. 
82
 
     This must be first. */
83
 
  generic_img_private_t gen; 
84
 
 
85
 
  access_mode_t access_mode;
86
 
 
87
 
  /* Some of the more OS specific things. */
88
 
  /* Entry info for each track, add 1 for leadout. */
89
 
  struct cdrom_tocentry  tocent[CDIO_CD_MAX_TRACKS+1]; 
90
 
 
91
 
  struct cdrom_tochdr    tochdr;
92
 
 
93
 
} _img_private_t;
94
 
 
95
 
/* Some ioctl() errno values which occur when the tray is empty */
96
 
#define ERRNO_TRAYEMPTY(errno)  \
97
 
        ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
98
 
 
99
 
/**** prototypes for static functions ****/
100
 
static bool is_cdrom_linux(const char *drive, char *mnttype);
101
 
static bool read_toc_linux (void *p_user_data);
102
 
static int  run_scsi_cmd_linux( const void *p_user_data, 
103
 
                                unsigned int i_timeout,
104
 
                                unsigned int i_cdb, 
105
 
                                const scsi_mmc_cdb_t *p_cdb, 
106
 
                                scsi_mmc_direction_t e_direction, 
107
 
                                unsigned int i_buf, 
108
 
                                /*in/out*/ void *p_buf );
109
 
static access_mode_t 
110
 
 
111
 
str_to_access_mode_linux(const char *psz_access_mode) 
112
 
{
113
 
  const access_mode_t default_access_mode = _AM_IOCTL;
114
 
 
115
 
  if (NULL==psz_access_mode) return default_access_mode;
116
 
  
117
 
  if (!strcmp(psz_access_mode, "IOCTL"))
118
 
    return _AM_IOCTL;
119
 
  else if (!strcmp(psz_access_mode, "READ_CD"))
120
 
    return _AM_READ_CD;
121
 
  else if (!strcmp(psz_access_mode, "READ_10"))
122
 
    return _AM_READ_10;
123
 
  else {
124
 
    cdio_warn ("unknown access type: %s. Default IOCTL used.", 
125
 
               psz_access_mode);
126
 
    return default_access_mode;
127
 
  }
128
 
}
129
 
 
130
 
static char *
131
 
check_mounts_linux(const char *mtab)
132
 
{
133
 
  FILE *mntfp;
134
 
  struct mntent *mntent;
135
 
  
136
 
  mntfp = setmntent(mtab, "r");
137
 
  if ( mntfp != NULL ) {
138
 
    char *tmp;
139
 
    char *mnt_type;
140
 
    char *mnt_dev;
141
 
    
142
 
    while ( (mntent=getmntent(mntfp)) != NULL ) {
143
 
      mnt_type = malloc(strlen(mntent->mnt_type) + 1);
144
 
      if (mnt_type == NULL)
145
 
        continue;  /* maybe you'll get lucky next time. */
146
 
      
147
 
      mnt_dev = malloc(strlen(mntent->mnt_fsname) + 1);
148
 
      if (mnt_dev == NULL) {
149
 
        free(mnt_type);
150
 
        continue;
151
 
      }
152
 
      
153
 
      strcpy(mnt_type, mntent->mnt_type);
154
 
      strcpy(mnt_dev, mntent->mnt_fsname);
155
 
      
156
 
      /* Handle "supermount" filesystem mounts */
157
 
      if ( strcmp(mnt_type, "supermount") == 0 ) {
158
 
        tmp = strstr(mntent->mnt_opts, "fs=");
159
 
        if ( tmp ) {
160
 
          free(mnt_type);
161
 
          mnt_type = strdup(tmp + strlen("fs="));
162
 
          if ( mnt_type ) {
163
 
            tmp = strchr(mnt_type, ',');
164
 
            if ( tmp ) {
165
 
              *tmp = '\0';
166
 
            }
167
 
          }
168
 
        }
169
 
        tmp = strstr(mntent->mnt_opts, "dev=");
170
 
        if ( tmp ) {
171
 
          free(mnt_dev);
172
 
          mnt_dev = strdup(tmp + strlen("dev="));
173
 
          if ( mnt_dev ) {
174
 
            tmp = strchr(mnt_dev, ',');
175
 
            if ( tmp ) {
176
 
              *tmp = '\0';
177
 
            }
178
 
          }
179
 
        }
180
 
      }
181
 
      if ( strcmp(mnt_type, "iso9660") == 0 ) {
182
 
        if (is_cdrom_linux(mnt_dev, mnt_type) > 0) {
183
 
          free(mnt_type);
184
 
          endmntent(mntfp);
185
 
          return mnt_dev;
186
 
        }
187
 
      }
188
 
      free(mnt_dev);
189
 
      free(mnt_type);
190
 
    }
191
 
    endmntent(mntfp);
192
 
  }
193
 
  return NULL;
194
 
}
195
 
 
196
 
/*!
197
 
  Return the value associated with the key "arg".
198
 
*/
199
 
static const char *
200
 
get_arg_linux (void *env, const char key[])
201
 
{
202
 
  _img_private_t *_obj = env;
203
 
 
204
 
  if (!strcmp (key, "source")) {
205
 
    return _obj->gen.source_name;
206
 
  } else if (!strcmp (key, "access-mode")) {
207
 
    switch (_obj->access_mode) {
208
 
    case _AM_IOCTL:
209
 
      return "ioctl";
210
 
    case _AM_READ_CD:
211
 
      return "READ_CD";
212
 
    case _AM_READ_10:
213
 
      return "READ_10";
214
 
    case _AM_NONE:
215
 
      return "no access method";
216
 
    }
217
 
  } 
218
 
  return NULL;
219
 
}
220
 
 
221
 
#undef USE_LINUX_CAP
222
 
#ifdef USE_LINUX_CAP
223
 
/*!
224
 
  Return the the kind of drive capabilities of device.
225
 
 
226
 
  Note: string is malloc'd so caller should free() then returned
227
 
  string when done with it.
228
 
 
229
 
 */
230
 
static void
231
 
get_drive_cap_linux (const void *p_user_data,
232
 
                     /*out*/ cdio_drive_read_cap_t  *p_read_cap,
233
 
                     /*out*/ cdio_drive_write_cap_t *p_write_cap,
234
 
                     /*out*/ cdio_drive_misc_cap_t  *p_misc_cap)
235
 
{
236
 
  const _img_private_t *p_env = p_user_data;
237
 
  int32_t i_drivetype;
238
 
 
239
 
  i_drivetype = ioctl (p_env->gen.fd, CDROM_GET_CAPABILITY, CDSL_CURRENT);
240
 
 
241
 
  if (i_drivetype < 0) {
242
 
    *p_read_cap  = CDIO_DRIVE_CAP_ERROR;
243
 
    *p_write_cap = CDIO_DRIVE_CAP_ERROR;
244
 
    *p_misc_cap  = CDIO_DRIVE_CAP_ERROR;
245
 
    return;
246
 
  }
247
 
  
248
 
  *p_read_cap  = 0;
249
 
  *p_write_cap = 0;
250
 
  *p_misc_cap  = 0;
251
 
 
252
 
  /* Reader */
253
 
  if (i_drivetype & CDC_PLAY_AUDIO) 
254
 
    *p_read_cap  |= CDIO_DRIVE_CAP_READ_AUDIO;
255
 
  if (i_drivetype & CDC_CD_R) 
256
 
    *p_read_cap  |= CDIO_DRIVE_CAP_READ_CD_R;
257
 
  if (i_drivetype & CDC_CD_RW) 
258
 
    *p_read_cap  |= CDIO_DRIVE_CAP_READ_CD_RW;
259
 
  if (i_drivetype & CDC_DVD) 
260
 
    *p_read_cap  |= CDIO_DRIVE_CAP_READ_DVD_ROM;
261
 
 
262
 
  /* Writer */
263
 
  if (i_drivetype & CDC_CD_RW) 
264
 
    *p_read_cap  |= CDIO_DRIVE_CAP_WRITE_CD_RW;
265
 
  if (i_drivetype & CDC_DVD_R) 
266
 
    *p_read_cap  |= CDIO_DRIVE_CAP_WRITE_DVD_R;
267
 
  if (i_drivetype & CDC_DVD_RAM) 
268
 
    *p_read_cap  |= CDIO_DRIVE_CAP_WRITE_DVD_RAM;
269
 
 
270
 
  /* Misc */
271
 
  if (i_drivetype & CDC_CLOSE_TRAY) 
272
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_CLOSE_TRAY;
273
 
  if (i_drivetype & CDC_OPEN_TRAY) 
274
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_EJECT;
275
 
  if (i_drivetype & CDC_LOCK) 
276
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_LOCK;
277
 
  if (i_drivetype & CDC_SELECT_SPEED) 
278
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_SELECT_SPEED;
279
 
  if (i_drivetype & CDC_SELECT_DISC) 
280
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_SELECT_DISC;
281
 
  if (i_drivetype & CDC_MULTI_SESSION) 
282
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_MULTI_SESSION;
283
 
  if (i_drivetype & CDC_MEDIA_CHANGED) 
284
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED;
285
 
  if (i_drivetype & CDC_RESET) 
286
 
    *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_RESET;
287
 
}
288
 
#endif
289
 
 
290
 
/*!
291
 
  Return the media catalog number MCN.
292
 
 
293
 
  Note: string is malloc'd so caller should free() then returned
294
 
  string when done with it.
295
 
 
296
 
 */
297
 
static char *
298
 
get_mcn_linux (const void *p_user_data) {
299
 
 
300
 
  struct cdrom_mcn mcn;
301
 
  const _img_private_t *p_env = p_user_data;
302
 
  memset(&mcn, 0, sizeof(mcn));
303
 
  if (ioctl(p_env->gen.fd, CDROM_GET_MCN, &mcn) != 0)
304
 
    return NULL;
305
 
  return strdup(mcn.medium_catalog_number);
306
 
}
307
 
 
308
 
/*!  
309
 
  Get format of track. 
310
 
*/
311
 
static track_format_t
312
 
get_track_format_linux(void *p_user_data, track_t i_track) 
313
 
{
314
 
  _img_private_t *p_env = p_user_data;
315
 
  
316
 
  if ( !p_env ) return TRACK_FORMAT_ERROR;
317
 
 
318
 
  if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
319
 
 
320
 
  if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track) 
321
 
      || i_track < p_env->gen.i_first_track)
322
 
    return TRACK_FORMAT_ERROR;
323
 
 
324
 
  i_track -= p_env->gen.i_first_track;
325
 
 
326
 
  /* This is pretty much copied from the "badly broken" cdrom_count_tracks
327
 
     in linux/cdrom.c.
328
 
   */
329
 
  if (p_env->tocent[i_track].cdte_ctrl & CDIO_CDROM_DATA_TRACK) {
330
 
    if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK)
331
 
      return TRACK_FORMAT_CDI;
332
 
    else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK)
333
 
      return TRACK_FORMAT_XA;
334
 
    else
335
 
      return TRACK_FORMAT_DATA;
336
 
  } else
337
 
    return TRACK_FORMAT_AUDIO;
338
 
  
339
 
}
340
 
 
341
 
/*!
342
 
  Return true if we have XA data (green, mode2 form1) or
343
 
  XA data (green, mode2 form2). That is track begins:
344
 
  sync - header - subheader
345
 
  12     4      -  8
346
 
 
347
 
  FIXME: there's gotta be a better design for this and get_track_format?
348
 
*/
349
 
static bool
350
 
get_track_green_linux(void *p_user_data, track_t i_track) 
351
 
{
352
 
  _img_private_t *p_env = p_user_data;
353
 
  
354
 
  if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
355
 
 
356
 
  if (i_track >= (p_env->gen.i_tracks+p_env->gen.i_first_track) 
357
 
      || i_track < p_env->gen.i_first_track)
358
 
    return false;
359
 
 
360
 
  i_track -= p_env->gen.i_first_track;
361
 
 
362
 
  /* FIXME: Dunno if this is the right way, but it's what 
363
 
     I was using in cd-info for a while.
364
 
   */
365
 
  return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0);
366
 
}
367
 
 
368
 
/*!  
369
 
  Return the starting MSF (minutes/secs/frames) for track number
370
 
  track_num in obj.  Track numbers usually start at something 
371
 
  greater than 0, usually 1.
372
 
 
373
 
  The "leadout" track is specified either by
374
 
  using i_track LEADOUT_TRACK or the total tracks+1.
375
 
  False is returned if there is no track entry.
376
 
*/
377
 
static bool
378
 
get_track_msf_linux(void *p_user_data, track_t i_track, msf_t *msf)
379
 
{
380
 
  _img_private_t *p_env = p_user_data;
381
 
 
382
 
  if (NULL == msf) return false;
383
 
 
384
 
  if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
385
 
 
386
 
  if (i_track == CDIO_CDROM_LEADOUT_TRACK) 
387
 
    i_track = p_env->gen.i_tracks + p_env->gen.i_first_track;
388
 
 
389
 
  if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track) 
390
 
      || i_track < p_env->gen.i_first_track) {
391
 
    return false;
392
 
  } else {
393
 
    struct cdrom_msf0  *msf0= 
394
 
      &p_env->tocent[i_track-p_env->gen.i_first_track].cdte_addr.msf;
395
 
    msf->m = cdio_to_bcd8(msf0->minute);
396
 
    msf->s = cdio_to_bcd8(msf0->second);
397
 
    msf->f = cdio_to_bcd8(msf0->frame);
398
 
    return true;
399
 
  }
400
 
}
401
 
 
402
 
/*!
403
 
  Eject media in CD drive. 
404
 
  Return 0 if success and 1 for failure, and 2 if no routine.
405
 
 */
406
 
static int 
407
 
eject_media_linux (void *p_user_data) {
408
 
 
409
 
  _img_private_t *p_env = p_user_data;
410
 
  int ret=2;
411
 
  int status;
412
 
  int fd;
413
 
 
414
 
  if ((fd = open (p_env->gen.source_name, O_RDONLY|O_NONBLOCK)) > -1) {
415
 
    if((status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
416
 
      switch(status) {
417
 
      case CDS_TRAY_OPEN:
418
 
        if((ret = ioctl(fd, CDROMCLOSETRAY)) != 0) {
419
 
          cdio_warn ("ioctl CDROMCLOSETRAY failed: %s\n", strerror(errno));  
420
 
          ret = 1;
421
 
        }
422
 
        break;
423
 
      case CDS_DISC_OK:
424
 
        if((ret = ioctl(fd, CDROMEJECT)) != 0) {
425
 
          int eject_error = errno;
426
 
          /* Try ejecting the MMC way... */
427
 
          ret = scsi_mmc_eject_media(p_env->gen.cdio);
428
 
          if (0 != ret) {
429
 
            cdio_warn("ioctl CDROMEJECT failed: %s\n", 
430
 
                      strerror(eject_error));
431
 
            ret = 1;
432
 
          }
433
 
        }
434
 
        /* force kernel to reread partition table when new disc inserted */
435
 
        ret = ioctl(p_env->gen.fd, BLKRRPART);
436
 
        break;
437
 
      default:
438
 
        cdio_warn ("Unknown CD-ROM (%d)\n", status);
439
 
        ret = 1;
440
 
      }
441
 
    } else {
442
 
      cdio_warn ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
443
 
      ret=1;
444
 
    }
445
 
    close(fd);
446
 
  } else
447
 
    ret = 2;
448
 
  close(p_env->gen.fd);
449
 
  p_env->gen.fd = -1;
450
 
  return ret;
451
 
}
452
 
 
453
 
/*! 
454
 
  Get disc type associated with the cd object.
455
 
*/
456
 
static discmode_t
457
 
get_discmode_linux (void *p_user_data)
458
 
{
459
 
  _img_private_t *p_env = p_user_data;
460
 
 
461
 
  int32_t i_discmode;
462
 
 
463
 
  /* See if this is a DVD. */
464
 
  cdio_dvd_struct_t dvd;  /* DVD READ STRUCT for layer 0. */
465
 
 
466
 
  dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
467
 
  dvd.physical.layer_num = 0;
468
 
  if (0 == ioctl (p_env->gen.fd, DVD_READ_STRUCT, &dvd)) {
469
 
    switch(dvd.physical.layer[0].book_type) {
470
 
    case CDIO_DVD_BOOK_DVD_ROM:  return CDIO_DISC_MODE_DVD_ROM;
471
 
    case CDIO_DVD_BOOK_DVD_RAM:  return CDIO_DISC_MODE_DVD_RAM;
472
 
    case CDIO_DVD_BOOK_DVD_R:    return CDIO_DISC_MODE_DVD_R;
473
 
    case CDIO_DVD_BOOK_DVD_RW:   return CDIO_DISC_MODE_DVD_RW;
474
 
    case CDIO_DVD_BOOK_DVD_PR:   return CDIO_DISC_MODE_DVD_PR;
475
 
    case CDIO_DVD_BOOK_DVD_PRW:  return CDIO_DISC_MODE_DVD_PRW;
476
 
    default:                     return CDIO_DISC_MODE_DVD_OTHER;
477
 
    }
478
 
  }
479
 
 
480
 
  i_discmode = ioctl (p_env->gen.fd, CDROM_DISC_STATUS);
481
 
  
482
 
  if (i_discmode < 0) return CDIO_DISC_MODE_ERROR;
483
 
 
484
 
  /* FIXME Need to add getting DVD types. */
485
 
  switch(i_discmode) {
486
 
  case CDS_AUDIO:
487
 
    return CDIO_DISC_MODE_CD_DA;
488
 
  case CDS_DATA_1:
489
 
  case CDS_DATA_2:
490
 
    return CDIO_DISC_MODE_CD_DATA;
491
 
  case CDS_MIXED:
492
 
    return CDIO_DISC_MODE_CD_MIXED;
493
 
  case CDS_XA_2_1:
494
 
  case CDS_XA_2_2:
495
 
    return CDIO_DISC_MODE_CD_XA;
496
 
  case CDS_NO_INFO:
497
 
    return CDIO_DISC_MODE_NO_INFO;
498
 
  default:
499
 
    return CDIO_DISC_MODE_ERROR;
500
 
  }
501
 
}
502
 
 
503
 
/* Check a drive to see if it is a CD-ROM 
504
 
   Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive
505
 
   and -1 if no device exists .
506
 
*/
507
 
static bool
508
 
is_cdrom_linux(const char *drive, char *mnttype)
509
 
{
510
 
  bool is_cd=false;
511
 
  int cdfd;
512
 
  struct cdrom_tochdr    tochdr;
513
 
  
514
 
  /* If it doesn't exist, return -1 */
515
 
  if ( !cdio_is_device_quiet_generic(drive) ) {
516
 
    return(false);
517
 
  }
518
 
  
519
 
  /* If it does exist, verify that it's an available CD-ROM */
520
 
  cdfd = open(drive, (O_RDONLY|O_NONBLOCK), 0);
521
 
  if ( cdfd >= 0 ) {
522
 
    if ( ioctl(cdfd, CDROMREADTOCHDR, &tochdr) != -1 ) {
523
 
      is_cd = true;
524
 
    }
525
 
    close(cdfd);
526
 
    }
527
 
  /* Even if we can't read it, it might be mounted */
528
 
  else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) {
529
 
    is_cd = true;
530
 
  }
531
 
  return(is_cd);
532
 
}
533
 
 
534
 
/* MMC driver to read audio sectors. 
535
 
   Can read only up to 25 blocks.
536
 
*/
537
 
static int
538
 
_read_audio_sectors_linux (void *p_user_data, void *buf, lsn_t lsn, 
539
 
                           unsigned int nblocks)
540
 
{
541
 
  _img_private_t *p_env = p_user_data;
542
 
  return scsi_mmc_read_sectors( p_env->gen.cdio, buf, lsn, 
543
 
                                CDIO_MMC_READ_TYPE_CDDA, nblocks);
544
 
}
545
 
 
546
 
/* Packet driver to read mode2 sectors. 
547
 
   Can read only up to 25 blocks.
548
 
*/
549
 
static int
550
 
_read_mode2_sectors_mmc (_img_private_t *p_env, void *p_buf, lba_t lba, 
551
 
                         unsigned int nblocks, bool b_read_10)
552
 
{
553
 
  scsi_mmc_cdb_t cdb = {{0, }};
554
 
 
555
 
  CDIO_MMC_SET_READ_LBA(cdb.field, lba);
556
 
 
557
 
  if (b_read_10) {
558
 
    int retval;
559
 
    
560
 
    CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_10);
561
 
    CDIO_MMC_SET_READ_LENGTH16(cdb.field, nblocks);
562
 
 
563
 
    if ((retval = scsi_mmc_set_blocksize (p_env->gen.cdio, M2RAW_SECTOR_SIZE)))
564
 
      return retval;
565
 
    
566
 
    if ((retval = run_scsi_cmd_linux (p_env, 0, 
567
 
                                      scsi_mmc_get_cmd_len(cdb.field[0]),
568
 
                                      &cdb, 
569
 
                                      SCSI_MMC_DATA_READ,
570
 
                                      M2RAW_SECTOR_SIZE * nblocks, 
571
 
                                      p_buf)))
572
 
      {
573
 
        scsi_mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
574
 
        return retval;
575
 
      }
576
 
    
577
 
    if ((retval = scsi_mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE)))
578
 
      return retval;
579
 
  } else
580
 
 
581
 
    cdb.field[1] = 0; /* sector size mode2 */
582
 
    cdb.field[9] = 0x58; /* 2336 mode2 */
583
 
 
584
 
    CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
585
 
    CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks);
586
 
 
587
 
    return run_scsi_cmd_linux (p_env, 0, 
588
 
                               scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, 
589
 
                               SCSI_MMC_DATA_READ,
590
 
                               M2RAW_SECTOR_SIZE * nblocks, p_buf);
591
 
  
592
 
  return 0;
593
 
}
594
 
 
595
 
static int
596
 
_read_mode2_sectors (_img_private_t *p_env, void *p_buf, lba_t lba, 
597
 
                     unsigned int nblocks, bool b_read_10)
598
 
{
599
 
  unsigned int l = 0;
600
 
  int retval = 0;
601
 
 
602
 
  while (nblocks > 0)
603
 
    {
604
 
      const unsigned nblocks2 = (nblocks > 25) ? 25 : nblocks;
605
 
      void *p_buf2 = ((char *)p_buf ) + (l * M2RAW_SECTOR_SIZE);
606
 
      
607
 
      retval |= _read_mode2_sectors_mmc (p_env, p_buf2, lba + l, 
608
 
                                         nblocks2, b_read_10);
609
 
 
610
 
      if (retval)
611
 
        break;
612
 
 
613
 
      nblocks -= nblocks2;
614
 
      l += nblocks2;
615
 
    }
616
 
 
617
 
  return retval;
618
 
}
619
 
 
620
 
/*!
621
 
   Reads a single mode1 sector from cd device into data starting
622
 
   from lsn. Returns 0 if no error. 
623
 
 */
624
 
static int
625
 
_read_mode1_sector_linux (void *p_user_data, void *p_data, lsn_t lsn, 
626
 
                         bool b_form2)
627
 
{
628
 
 
629
 
#if FIXED
630
 
  char buf[M2RAW_SECTOR_SIZE] = { 0, };
631
 
  struct cdrom_msf *p_msf = (struct cdrom_msf *) &buf;
632
 
  msf_t _msf;
633
 
 
634
 
  _img_private_t *p_env = p_user_data;
635
 
 
636
 
  cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
637
 
  msf->cdmsf_min0 = cdio_from_bcd8(_msf.m);
638
 
  msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s);
639
 
  msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f);
640
 
 
641
 
 retry:
642
 
  switch (p_env->access_mode)
643
 
    {
644
 
    case _AM_NONE:
645
 
      cdio_warn ("no way to read mode1");
646
 
      return 1;
647
 
      break;
648
 
      
649
 
    case _AM_IOCTL:
650
 
      if (ioctl (p_env->gen.fd, CDROMREADMODE1, &buf) == -1)
651
 
        {
652
 
          perror ("ioctl()");
653
 
          return 1;
654
 
          /* exit (EXIT_FAILURE); */
655
 
        }
656
 
      break;
657
 
      
658
 
    case _AM_READ_CD:
659
 
    case _AM_READ_10:
660
 
      if (_read_mode2_sectors (p_env->gen.fd, buf, lsn, 1, 
661
 
                                      (p_env->access_mode == _AM_READ_10)))
662
 
        {
663
 
          perror ("ioctl()");
664
 
          if (p_env->access_mode == _AM_READ_CD)
665
 
            {
666
 
              cdio_info ("READ_CD failed; switching to READ_10 mode...");
667
 
              p_env->access_mode = _AM_READ_10;
668
 
              goto retry;
669
 
            }
670
 
          else
671
 
            {
672
 
              cdio_info ("READ_10 failed; switching to ioctl(CDROMREADMODE2) mode...");
673
 
              p_env->access_mode = _AM_IOCTL;
674
 
              goto retry;
675
 
            }
676
 
          return 1;
677
 
        }
678
 
      break;
679
 
    }
680
 
 
681
 
  memcpy (data, buf + CDIO_CD_SYNC_SIZE + CDIO_CD_HEADER_SIZE, 
682
 
          b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
683
 
  
684
 
#else
685
 
  return cdio_generic_read_form1_sector(p_user_data, p_data, lsn);
686
 
#endif
687
 
  return 0;
688
 
}
689
 
 
690
 
/*!
691
 
   Reads nblocks of mode2 sectors from cd device into data starting
692
 
   from lsn.
693
 
   Returns 0 if no error. 
694
 
 */
695
 
static int
696
 
_read_mode1_sectors_linux (void *p_user_data, void *p_data, lsn_t lsn, 
697
 
                          bool b_form2, unsigned int nblocks)
698
 
{
699
 
  _img_private_t *p_env = p_user_data;
700
 
  unsigned int i;
701
 
  int retval;
702
 
  unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
703
 
 
704
 
  for (i = 0; i < nblocks; i++) {
705
 
    if ( (retval = _read_mode1_sector_linux (p_env,
706
 
                                            ((char *)p_data) + (blocksize*i),
707
 
                                            lsn + i, b_form2)) )
708
 
      return retval;
709
 
  }
710
 
  return 0;
711
 
}
712
 
 
713
 
/*!
714
 
   Reads a single mode2 sector from cd device into data starting
715
 
   from lsn. Returns 0 if no error. 
716
 
 */
717
 
static int
718
 
_read_mode2_sector_linux (void *p_user_data, void *p_data, lsn_t lsn, 
719
 
                          bool b_form2)
720
 
{
721
 
  char buf[M2RAW_SECTOR_SIZE] = { 0, };
722
 
  struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
723
 
  msf_t _msf;
724
 
 
725
 
  _img_private_t *p_env = p_user_data;
726
 
 
727
 
  cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
728
 
  msf->cdmsf_min0 = cdio_from_bcd8(_msf.m);
729
 
  msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s);
730
 
  msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f);
731
 
 
732
 
 retry:
733
 
  switch (p_env->access_mode)
734
 
    {
735
 
    case _AM_NONE:
736
 
      cdio_warn ("no way to read mode2");
737
 
      return 1;
738
 
      break;
739
 
      
740
 
    case _AM_IOCTL:
741
 
      if (ioctl (p_env->gen.fd, CDROMREADMODE2, &buf) == -1)
742
 
        {
743
 
          perror ("ioctl()");
744
 
          return 1;
745
 
          /* exit (EXIT_FAILURE); */
746
 
        }
747
 
      break;
748
 
      
749
 
    case _AM_READ_CD:
750
 
    case _AM_READ_10:
751
 
      if (_read_mode2_sectors (p_env, buf, lsn, 1, 
752
 
                               (p_env->access_mode == _AM_READ_10)))
753
 
        {
754
 
          perror ("ioctl()");
755
 
          if (p_env->access_mode == _AM_READ_CD)
756
 
            {
757
 
              cdio_info ("READ_CD failed; switching to READ_10 mode...");
758
 
              p_env->access_mode = _AM_READ_10;
759
 
              goto retry;
760
 
            }
761
 
          else
762
 
            {
763
 
              cdio_info ("READ_10 failed; switching to ioctl(CDROMREADMODE2) mode...");
764
 
              p_env->access_mode = _AM_IOCTL;
765
 
              goto retry;
766
 
            }
767
 
          return 1;
768
 
        }
769
 
      break;
770
 
    }
771
 
 
772
 
  if (b_form2)
773
 
    memcpy (p_data, buf, M2RAW_SECTOR_SIZE);
774
 
  else
775
 
    memcpy (((char *)p_data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
776
 
  
777
 
  return 0;
778
 
}
779
 
 
780
 
/*!
781
 
   Reads nblocks of mode2 sectors from cd device into data starting
782
 
   from lsn.
783
 
   Returns 0 if no error. 
784
 
 */
785
 
static int
786
 
_read_mode2_sectors_linux (void *p_user_data, void *data, lsn_t lsn, 
787
 
                          bool b_form2, unsigned int nblocks)
788
 
{
789
 
  _img_private_t *p_env = p_user_data;
790
 
  unsigned int i;
791
 
  unsigned int i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
792
 
 
793
 
  /* For each frame, pick out the data part we need */
794
 
  for (i = 0; i < nblocks; i++) {
795
 
    int retval;
796
 
    if ( (retval = _read_mode2_sector_linux (p_env, 
797
 
                                            ((char *)data) + (i_blocksize*i),
798
 
                                            lsn + i, b_form2)) )
799
 
      return retval;
800
 
  }
801
 
  return 0;
802
 
}
803
 
 
804
 
/*! 
805
 
  Read and cache the CD's Track Table of Contents and track info.
806
 
  Return false if successful or true if an error.
807
 
*/
808
 
static bool
809
 
read_toc_linux (void *p_user_data) 
810
 
{
811
 
  _img_private_t *p_env = p_user_data;
812
 
  int i;
813
 
 
814
 
  /* read TOC header */
815
 
  if ( ioctl(p_env->gen.fd, CDROMREADTOCHDR, &p_env->tochdr) == -1 ) {
816
 
    cdio_warn("%s: %s\n", 
817
 
            "error in ioctl CDROMREADTOCHDR", strerror(errno));
818
 
    return false;
819
 
  }
820
 
 
821
 
  p_env->gen.i_first_track = p_env->tochdr.cdth_trk0;
822
 
  p_env->gen.i_tracks      = p_env->tochdr.cdth_trk1;
823
 
 
824
 
  /* read individual tracks */
825
 
  for (i= p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++) {
826
 
    p_env->tocent[i-p_env->gen.i_first_track].cdte_track = i;
827
 
    p_env->tocent[i-p_env->gen.i_first_track].cdte_format = CDROM_MSF;
828
 
    if ( ioctl(p_env->gen.fd, CDROMREADTOCENTRY, 
829
 
               &p_env->tocent[i-p_env->gen.i_first_track]) == -1 ) {
830
 
      cdio_warn("%s %d: %s\n",
831
 
              "error in ioctl CDROMREADTOCENTRY for track", 
832
 
              i, strerror(errno));
833
 
      return false;
834
 
    }
835
 
    /****
836
 
    struct cdrom_msf0 *msf= &env->tocent[i-1].cdte_addr.msf;
837
 
    
838
 
    fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
839
 
             i, msf->minute, msf->second, msf->frame);
840
 
    ****/
841
 
 
842
 
  }
843
 
 
844
 
  /* read the lead-out track */
845
 
  p_env->tocent[p_env->gen.i_tracks].cdte_track = CDIO_CDROM_LEADOUT_TRACK;
846
 
  p_env->tocent[p_env->gen.i_tracks].cdte_format = CDROM_MSF;
847
 
 
848
 
  if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY, 
849
 
            &p_env->tocent[p_env->gen.i_tracks]) == -1 ) {
850
 
    cdio_warn("%s: %s\n", 
851
 
             "error in ioctl CDROMREADTOCENTRY for lead-out",
852
 
            strerror(errno));
853
 
    return false;
854
 
  }
855
 
 
856
 
  /*
857
 
  struct cdrom_msf0 *msf= &env->tocent[p_env->gen.i_tracks].cdte_addr.msf;
858
 
 
859
 
  fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
860
 
           i, msf->minute, msf->second, msf->frame);
861
 
  */
862
 
 
863
 
  p_env->gen.toc_init = true;
864
 
  return true;
865
 
}
866
 
 
867
 
/*!
868
 
  Run a SCSI MMC command. 
869
 
 
870
 
  cdio          CD structure set by cdio_open().
871
 
  i_timeout     time in milliseconds we will wait for the command
872
 
                to complete. If this value is -1, use the default 
873
 
                time-out value.
874
 
  p_buf         Buffer for data, both sending and receiving
875
 
  i_buf         Size of buffer
876
 
  e_direction   direction the transfer is to go.
877
 
  cdb           CDB bytes. All values that are needed should be set on 
878
 
                input. We'll figure out what the right CDB length should be.
879
 
 
880
 
  We return true if command completed successfully and false if not.
881
 
 */
882
 
static int
883
 
run_scsi_cmd_linux( const void *p_user_data, 
884
 
                    unsigned int i_timeout_ms,
885
 
                    unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb, 
886
 
                    scsi_mmc_direction_t e_direction, 
887
 
                    unsigned int i_buf, /*in/out*/ void *p_buf )
888
 
{
889
 
  const _img_private_t *p_env = p_user_data;
890
 
  struct cdrom_generic_command cgc;
891
 
  memset (&cgc, 0, sizeof (struct cdrom_generic_command));
892
 
  memcpy(&cgc.cmd, p_cdb, i_cdb);
893
 
  cgc.buflen = i_buf;
894
 
  cgc.buffer = p_buf;
895
 
  cgc.data_direction = (SCSI_MMC_DATA_READ == cgc.data_direction)
896
 
    ? CGC_DATA_READ : CGC_DATA_WRITE;
897
 
 
898
 
#ifdef HAVE_LINUX_CDROM_TIMEOUT
899
 
  cgc.timeout = i_timeout_ms;
900
 
#endif
901
 
 
902
 
  return ioctl (p_env->gen.fd, CDROM_SEND_PACKET, &cgc);
903
 
}
904
 
 
905
 
/*!
906
 
   Return the size of the CD in logical block address (LBA) units.
907
 
 */
908
 
static uint32_t 
909
 
stat_size_linux (void *p_user_data)
910
 
{
911
 
  _img_private_t *p_env = p_user_data;
912
 
 
913
 
  struct cdrom_tocentry tocent;
914
 
  uint32_t size;
915
 
 
916
 
  tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK;
917
 
  tocent.cdte_format = CDROM_LBA;
918
 
  if (ioctl (p_env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
919
 
    {
920
 
      perror ("ioctl(CDROMREADTOCENTRY)");
921
 
      exit (EXIT_FAILURE);
922
 
    }
923
 
 
924
 
  size = tocent.cdte_addr.lba;
925
 
 
926
 
  return size;
927
 
}
928
 
 
929
 
/*!
930
 
  Set the arg "key" with "value" in the source device.
931
 
  Currently "source" and "access-mode" are valid keys.
932
 
  "source" sets the source device in I/O operations 
933
 
  "access-mode" sets the the method of CD access 
934
 
 
935
 
  0 is returned if no error was found, and nonzero if there as an error.
936
 
*/
937
 
static int
938
 
set_arg_linux (void *p_user_data, const char key[], const char value[])
939
 
{
940
 
  _img_private_t *p_env = p_user_data;
941
 
 
942
 
  if (!strcmp (key, "source"))
943
 
    {
944
 
      if (!value)
945
 
        return -2;
946
 
 
947
 
      free (p_env->gen.source_name);
948
 
      
949
 
      p_env->gen.source_name = strdup (value);
950
 
    }
951
 
  else if (!strcmp (key, "access-mode"))
952
 
    {
953
 
      return str_to_access_mode_linux(value);
954
 
    }
955
 
  else 
956
 
    return -1;
957
 
 
958
 
  return 0;
959
 
}
960
 
 
961
 
/* checklist: /dev/cdrom, /dev/dvd /dev/hd?, /dev/scd? /dev/sr? */
962
 
static char checklist1[][40] = {
963
 
  {"cdrom"}, {"dvd"}, {""}
964
 
};
965
 
static char checklist2[][40] = {
966
 
  {"?a hd?"}, {"?0 scd?"}, {"?0 sr?"}, {""}
967
 
};
968
 
 
969
 
#endif /* HAVE_LINUX_CDROM */
970
 
 
971
 
/*!
972
 
  Return an array of strings giving possible CD devices.
973
 
 */
974
 
char **
975
 
cdio_get_devices_linux (void)
976
 
{
977
 
#ifndef HAVE_LINUX_CDROM
978
 
  return NULL;
979
 
#else
980
 
  unsigned int i;
981
 
  char drive[40];
982
 
  char *ret_drive;
983
 
  bool exists;
984
 
  char **drives = NULL;
985
 
  unsigned int num_drives=0;
986
 
  
987
 
  /* Scan the system for CD-ROM drives.
988
 
  */
989
 
  for ( i=0; strlen(checklist1[i]) > 0; ++i ) {
990
 
    sprintf(drive, "/dev/%s", checklist1[i]);
991
 
    if ( (exists=is_cdrom_linux(drive, NULL)) > 0 ) {
992
 
      cdio_add_device_list(&drives, drive, &num_drives);
993
 
    }
994
 
  }
995
 
 
996
 
  /* Now check the currently mounted CD drives */
997
 
  if (NULL != (ret_drive = check_mounts_linux("/etc/mtab"))) {
998
 
    cdio_add_device_list(&drives, ret_drive, &num_drives);
999
 
    free(ret_drive);
1000
 
  }
1001
 
  
1002
 
  /* Finally check possible mountable drives in /etc/fstab */
1003
 
  if (NULL != (ret_drive = check_mounts_linux("/etc/fstab"))) {
1004
 
    cdio_add_device_list(&drives, ret_drive, &num_drives);
1005
 
    free(ret_drive);
1006
 
  }
1007
 
 
1008
 
  /* Scan the system for CD-ROM drives.
1009
 
     Not always 100% reliable, so use the USE_MNTENT code above first.
1010
 
  */
1011
 
  for ( i=0; strlen(checklist2[i]) > 0; ++i ) {
1012
 
    unsigned int j;
1013
 
    char *insert;
1014
 
    exists = true;
1015
 
    for ( j=checklist2[i][1]; exists; ++j ) {
1016
 
      sprintf(drive, "/dev/%s", &checklist2[i][3]);
1017
 
      insert = strchr(drive, '?');
1018
 
      if ( insert != NULL ) {
1019
 
        *insert = j;
1020
 
      }
1021
 
      if ( (exists=is_cdrom_linux(drive, NULL)) > 0 ) {
1022
 
        cdio_add_device_list(&drives, drive, &num_drives);
1023
 
      }
1024
 
    }
1025
 
  }
1026
 
  cdio_add_device_list(&drives, NULL, &num_drives);
1027
 
  return drives;
1028
 
#endif /*HAVE_LINUX_CDROM*/
1029
 
}
1030
 
 
1031
 
/*!
1032
 
  Return a string containing the default CD device.
1033
 
 */
1034
 
char *
1035
 
cdio_get_default_device_linux(void)
1036
 
{
1037
 
#ifndef HAVE_LINUX_CDROM
1038
 
  return NULL;
1039
 
  
1040
 
#else
1041
 
  unsigned int i;
1042
 
  char drive[40];
1043
 
  bool exists;
1044
 
  char *ret_drive;
1045
 
 
1046
 
  /* Scan the system for CD-ROM drives.
1047
 
  */
1048
 
  for ( i=0; strlen(checklist1[i]) > 0; ++i ) {
1049
 
    sprintf(drive, "/dev/%s", checklist1[i]);
1050
 
    if ( (exists=is_cdrom_linux(drive, NULL)) > 0 ) {
1051
 
      return strdup(drive);
1052
 
    }
1053
 
  }
1054
 
 
1055
 
  /* Now check the currently mounted CD drives */
1056
 
  if (NULL != (ret_drive = check_mounts_linux("/etc/mtab")))
1057
 
    return ret_drive;
1058
 
  
1059
 
  /* Finally check possible mountable drives in /etc/fstab */
1060
 
  if (NULL != (ret_drive = check_mounts_linux("/etc/fstab")))
1061
 
    return ret_drive;
1062
 
 
1063
 
  /* Scan the system for CD-ROM drives.
1064
 
     Not always 100% reliable, so use the USE_MNTENT code above first.
1065
 
  */
1066
 
  for ( i=0; strlen(checklist2[i]) > 0; ++i ) {
1067
 
    unsigned int j;
1068
 
    char *insert;
1069
 
    exists = true;
1070
 
    for ( j=checklist2[i][1]; exists; ++j ) {
1071
 
      sprintf(drive, "/dev/%s", &checklist2[i][3]);
1072
 
      insert = strchr(drive, '?');
1073
 
      if ( insert != NULL ) {
1074
 
        *insert = j;
1075
 
      }
1076
 
      if ( (exists=is_cdrom_linux(drive, NULL)) > 0 ) {
1077
 
        return(strdup(drive));
1078
 
      }
1079
 
    }
1080
 
  }
1081
 
  return NULL;
1082
 
#endif /*HAVE_LINUX_CDROM*/
1083
 
}
1084
 
/*!
1085
 
  Initialization routine. This is the only thing that doesn't
1086
 
  get called via a function pointer. In fact *we* are the
1087
 
  ones to set that up.
1088
 
 */
1089
 
CdIo *
1090
 
cdio_open_linux (const char *psz_source_name)
1091
 
{
1092
 
  return cdio_open_am_linux(psz_source_name, NULL);
1093
 
}
1094
 
 
1095
 
/*!
1096
 
  Initialization routine. This is the only thing that doesn't
1097
 
  get called via a function pointer. In fact *we* are the
1098
 
  ones to set that up.
1099
 
 */
1100
 
CdIo *
1101
 
cdio_open_am_linux (const char *psz_orig_source, const char *access_mode)
1102
 
{
1103
 
 
1104
 
#ifdef HAVE_LINUX_CDROM
1105
 
  CdIo *ret;
1106
 
  _img_private_t *_data;
1107
 
  char *psz_source;
1108
 
 
1109
 
  cdio_funcs _funcs = {
1110
 
    .eject_media        = eject_media_linux,
1111
 
    .free               = cdio_generic_free,
1112
 
    .get_arg            = get_arg_linux,
1113
 
    .get_cdtext         = get_cdtext_generic,
1114
 
    .get_default_device = cdio_get_default_device_linux,
1115
 
    .get_devices        = cdio_get_devices_linux,
1116
 
    .get_discmode       = get_discmode_linux,
1117
 
#if USE_LINUX_CAP
1118
 
    .get_drive_cap      = get_drive_cap_linux,
1119
 
#else
1120
 
    .get_drive_cap      = scsi_mmc_get_drive_cap_generic,
1121
 
#endif
1122
 
    .get_first_track_num= get_first_track_num_generic,
1123
 
    .get_hwinfo         = NULL,
1124
 
    .get_mcn            = get_mcn_linux,
1125
 
    .get_num_tracks     = get_num_tracks_generic,
1126
 
    .get_track_format   = get_track_format_linux,
1127
 
    .get_track_green    = get_track_green_linux,
1128
 
    .get_track_lba      = NULL, /* This could be implemented if need be. */
1129
 
    .get_track_msf      = get_track_msf_linux,
1130
 
    .lseek              = cdio_generic_lseek,
1131
 
    .read               = cdio_generic_read,
1132
 
    .read_audio_sectors = _read_audio_sectors_linux,
1133
 
    .read_mode1_sector  = _read_mode1_sector_linux,
1134
 
    .read_mode1_sectors = _read_mode1_sectors_linux,
1135
 
    .read_mode2_sector  = _read_mode2_sector_linux,
1136
 
    .read_mode2_sectors = _read_mode2_sectors_linux,
1137
 
    .read_toc           = read_toc_linux,
1138
 
    .run_scsi_mmc_cmd   = run_scsi_cmd_linux,
1139
 
    .set_arg            = set_arg_linux,
1140
 
    .stat_size          = stat_size_linux
1141
 
  };
1142
 
 
1143
 
  _data                 = _cdio_malloc (sizeof (_img_private_t));
1144
 
 
1145
 
  _data->access_mode    = str_to_access_mode_linux(access_mode);
1146
 
  _data->gen.init       = false;
1147
 
  _data->gen.toc_init   = false;
1148
 
  _data->gen.fd         = -1;
1149
 
  _data->gen.b_cdtext_init  = false;
1150
 
  _data->gen.b_cdtext_error = false;
1151
 
 
1152
 
  if (NULL == psz_orig_source) {
1153
 
    psz_source=cdio_get_default_device_linux();
1154
 
    if (NULL == psz_source) return NULL;
1155
 
    set_arg_linux(_data, "source", psz_source);
1156
 
    free(psz_source);
1157
 
  } else {
1158
 
    if (cdio_is_device_generic(psz_orig_source))
1159
 
      set_arg_linux(_data, "source", psz_orig_source);
1160
 
    else {
1161
 
      /* The below would be okay if all device drivers worked this way. */
1162
 
#if 0
1163
 
      cdio_info ("source %s is not a device", psz_orig_source);
1164
 
#endif
1165
 
      return NULL;
1166
 
    }
1167
 
  }
1168
 
 
1169
 
  ret = cdio_new ((void *)_data, &_funcs);
1170
 
  if (ret == NULL) return NULL;
1171
 
 
1172
 
  if (cdio_generic_init(_data)) {
1173
 
    return ret;
1174
 
  } else {
1175
 
    cdio_generic_free (_data);
1176
 
    return NULL;
1177
 
  }
1178
 
  
1179
 
#else 
1180
 
  return NULL;
1181
 
#endif /* HAVE_LINUX_CDROM */
1182
 
 
1183
 
}
1184
 
 
1185
 
bool
1186
 
cdio_have_linux (void)
1187
 
{
1188
 
#ifdef HAVE_LINUX_CDROM
1189
 
  return true;
1190
 
#else 
1191
 
  return false;
1192
 
#endif /* HAVE_LINUX_CDROM */
1193
 
}