1 /*
2 Copyright (C) 2002-2006, 2009, 2011-2012, 2017
3 Rocky Bernstein <rocky@gnu.org>
4 Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27
28 #include <cdio/logging.h>
29 #include <cdio/sector.h>
30 #include <cdio/util.h>
31 #include <cdio/mmc.h>
32 #include "cdio_assert.h"
33 #include "cdio_private.h"
34
35 #define DEFAULT_CDIO_DEVICE "/vol/dev/aliases/cdrom0"
36
37 #ifdef HAVE_SOLARIS_CDROM
38
39 static char ** cdio_get_devices_solaris_cXtYdZs2(int flag);
40
41 #ifdef HAVE_GLOB_H
42 #include <glob.h>
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50
51 #ifdef HAVE_SYS_CDIO_H
52 # include <sys/cdio.h> /* CDIOCALLOW etc... */
53 #else
54 #error "You need <sys/cdio.h> to have CDROM support"
55 #endif
56
57 #include <sys/dkio.h>
58 #include <sys/scsi/generic/commands.h>
59 #include <sys/scsi/impl/uscsi.h>
60
61 #include <sys/stat.h>
62 #include <sys/types.h>
63 #include <sys/ioctl.h>
64 #include <dirent.h>
65 #include "cdtext_private.h"
66
67 /* not defined in dkio.h yet */
68 #define DK_DVDRW 0x13
69
70 /* reader */
71
72 typedef enum {
73 _AM_NONE,
74 _AM_SUN_CTRL_ATAPI,
75 _AM_SUN_CTRL_SCSI,
76 _AM_MMC_RDWR,
77 _AM_MMC_RDWR_EXCL
78 #ifdef FINISHED
79 _AM_READ_CD,
80 _AM_READ_10
81 #endif
82 } access_mode_t;
83
84
85 typedef struct {
86 /* Things common to all drivers like this.
87 This must be first. */
88 generic_img_private_t gen;
89
90 access_mode_t access_mode;
91
92 /* Some of the more OS specific things. */
93 /* Entry info for each track, add 1 for leadout. */
94 struct cdrom_tocentry tocent[CDIO_CD_MAX_TRACKS+1];
95
96 /* Track information */
97 struct cdrom_tochdr tochdr;
98 } _img_private_t;
99
100 /*!
101 Return the international standard recording code ISRC.
102
103 Note: string is malloc'd so caller should free() then returned
104 string when done with it.
105
106 */
107 static char *
get_track_isrc_solaris(const void * p_user_data,track_t i_track)108 get_track_isrc_solaris (const void *p_user_data, track_t i_track) {
109
110 const _img_private_t *p_env = p_user_data;
111 return mmc_get_track_isrc( p_env->gen.cdio, i_track );
112 }
113
114 static track_format_t get_track_format_solaris(void *p_user_data,
115 track_t i_track);
116
117 static access_mode_t
str_to_access_mode_solaris(const char * psz_access_mode)118 str_to_access_mode_solaris(const char *psz_access_mode)
119 {
120 const access_mode_t default_access_mode = _AM_SUN_CTRL_SCSI;
121
122 if (NULL==psz_access_mode) return default_access_mode;
123
124 if (!strcmp(psz_access_mode, "ATAPI"))
125 return _AM_SUN_CTRL_SCSI; /* force ATAPI to be SCSI */
126 else if (!strcmp(psz_access_mode, "SCSI"))
127 return _AM_SUN_CTRL_SCSI;
128 else if (!strcmp(psz_access_mode, "MMC_RDWR"))
129 return _AM_MMC_RDWR;
130 else if (!strcmp(psz_access_mode, "MMC_RDWR_EXCL"))
131 return _AM_MMC_RDWR_EXCL;
132 else {
133 cdio_warn ("unknown access type: %s. Default SCSI used.",
134 psz_access_mode);
135 return default_access_mode;
136 }
137 }
138
139
140 /*!
141 Pause playing CD through analog output
142
143 @param p_cdio the CD object to be acted upon.
144 */
145 static driver_return_code_t
audio_pause_solaris(void * p_user_data)146 audio_pause_solaris (void *p_user_data)
147 {
148
149 const _img_private_t *p_env = p_user_data;
150 return ioctl(p_env->gen.fd, CDROMPAUSE);
151 }
152
153 /*!
154 Playing starting at given MSF through analog output
155
156 @param p_cdio the CD object to be acted upon.
157 */
158 static driver_return_code_t
audio_play_msf_solaris(void * p_user_data,msf_t * p_start_msf,msf_t * p_end_msf)159 audio_play_msf_solaris (void *p_user_data, msf_t *p_start_msf,
160 msf_t *p_end_msf)
161 {
162
163 const _img_private_t *p_env = p_user_data;
164
165 struct cdrom_msf solaris_msf;
166 solaris_msf.cdmsf_min0 = cdio_from_bcd8(p_start_msf->m);
167 solaris_msf.cdmsf_sec0 = cdio_from_bcd8(p_start_msf->s);
168 solaris_msf.cdmsf_frame0 = cdio_from_bcd8(p_start_msf->f);
169 solaris_msf.cdmsf_min1 = cdio_from_bcd8(p_end_msf->m);
170 solaris_msf.cdmsf_sec1 = cdio_from_bcd8(p_end_msf->s);
171 solaris_msf.cdmsf_frame1 = cdio_from_bcd8(p_end_msf->f);
172
173 return ioctl(p_env->gen.fd, CDROMPLAYMSF, &solaris_msf);
174 }
175
176 /*!
177 Playing CD through analog output at the desired track and index
178
179 @param p_cdio the CD object to be acted upon.
180 @param p_track_index location to start/end.
181 */
182 static driver_return_code_t
audio_play_track_index_solaris(void * p_user_data,cdio_track_index_t * p_track_index)183 audio_play_track_index_solaris (void *p_user_data,
184 cdio_track_index_t *p_track_index)
185 {
186
187 const _img_private_t *p_env = p_user_data;
188 return ioctl(p_env->gen.fd, CDROMPLAYTRKIND, p_track_index);
189 }
190
191 /*!
192 Read Audio Subchannel information
193
194 @param p_cdio the CD object to be acted upon.
195
196 */
197 static driver_return_code_t
audio_read_subchannel_solaris(void * p_user_data,cdio_subchannel_t * p_subchannel)198 audio_read_subchannel_solaris (void *p_user_data,
199 cdio_subchannel_t *p_subchannel)
200 {
201 const _img_private_t *p_env = p_user_data;
202 struct cdrom_subchnl subchannel;
203 int i_rc;
204 p_subchannel->format = CDIO_CDROM_MSF;
205 i_rc = ioctl(p_env->gen.fd, CDROMSUBCHNL, &subchannel);
206 if (0 == i_rc) {
207 p_subchannel->control = subchannel.cdsc_ctrl;
208 p_subchannel->track = subchannel.cdsc_trk;
209 p_subchannel->index = subchannel.cdsc_ind;
210
211 p_subchannel->abs_addr.m =
212 cdio_to_bcd8(subchannel.cdsc_absaddr.msf.minute);
213 p_subchannel->abs_addr.s =
214 cdio_to_bcd8(subchannel.cdsc_absaddr.msf.second);
215 p_subchannel->abs_addr.f =
216 cdio_to_bcd8(subchannel.cdsc_absaddr.msf.frame);
217 p_subchannel->rel_addr.m =
218 cdio_to_bcd8(subchannel.cdsc_reladdr.msf.minute);
219 p_subchannel->rel_addr.s =
220 cdio_to_bcd8(subchannel.cdsc_reladdr.msf.second);
221 p_subchannel->rel_addr.f =
222 cdio_to_bcd8(subchannel.cdsc_reladdr.msf.frame);
223 p_subchannel->audio_status = subchannel.cdsc_audiostatus;
224
225 return DRIVER_OP_SUCCESS;
226 } else {
227 cdio_info ("ioctl CDROMSUBCHNL failed: %s\n", strerror(errno));
228 return DRIVER_OP_ERROR;
229 }
230 }
231
232 /*!
233 Resume playing an audio CD.
234
235 @param p_cdio the CD object to be acted upon.
236
237 */
238 static driver_return_code_t
audio_resume_solaris(void * p_user_data)239 audio_resume_solaris (void *p_user_data)
240 {
241
242 const _img_private_t *p_env = p_user_data;
243 return ioctl(p_env->gen.fd, CDROMRESUME, 0);
244 }
245
246 /*!
247 Resume playing an audio CD.
248
249 @param p_cdio the CD object to be acted upon.
250
251 */
252 static driver_return_code_t
audio_set_volume_solaris(void * p_user_data,cdio_audio_volume_t * p_volume)253 audio_set_volume_solaris (void *p_user_data,
254 cdio_audio_volume_t *p_volume) {
255
256 const _img_private_t *p_env = p_user_data;
257 return ioctl(p_env->gen.fd, CDROMVOLCTRL, p_volume);
258 }
259
260 /*!
261 Stop playing an audio CD.
262
263 @param p_user_data the CD object to be acted upon.
264
265 */
266 static driver_return_code_t
audio_stop_solaris(void * p_user_data)267 audio_stop_solaris (void *p_user_data)
268 {
269 const _img_private_t *p_env = p_user_data;
270 return ioctl(p_env->gen.fd, CDROMSTOP);
271 }
272
273 static int
cdio_decode_btl_number(char ** cpt,int stopper,int * no)274 cdio_decode_btl_number(char **cpt, int stopper, int *no)
275 {
276 *no = 0;
277 for ((*cpt)++; **cpt != stopper; (*cpt)++) {
278 if (**cpt < '0' || **cpt > '9')
279 return 0;
280 *no = *no * 10 + **cpt - '0';
281 }
282 return 1;
283 }
284
285 /* Read bus, target, lun from name "cXtYdZs2".
286 Return 0 if name is not of the desired form.
287 */
288 static int
cdio_decode_btl_solaris(char * name,int * busno,int * tgtno,int * lunno,int flag)289 cdio_decode_btl_solaris(char *name, int *busno, int *tgtno, int *lunno,
290 int flag)
291 {
292 char *cpt;
293 int ret;
294
295 *busno = *tgtno = *lunno = -1;
296 cpt = name;
297 if (*cpt != 'c')
298 return 0;
299 ret = cdio_decode_btl_number(&cpt, 't', busno);
300 if (ret <= 0)
301 return ret;
302 ret = cdio_decode_btl_number(&cpt, 'd', tgtno);
303 if (ret <= 0)
304 return ret;
305 ret = cdio_decode_btl_number(&cpt, 's', lunno);
306 if (ret <= 0)
307 return ret;
308 cpt++;
309 if (*cpt != '2' || *(cpt + 1) != 0)
310 return 0;
311 return 1;
312 }
313
314 static int
set_scsi_tuple_solaris(_img_private_t * p_env)315 set_scsi_tuple_solaris (_img_private_t *p_env)
316 {
317 int bus_no = -1, host_no = -1, channel_no = -1, target_no = -1, lun_no = -1;
318 int ret;
319 char tuple[160], *cpt;
320
321 cpt = strrchr(p_env->gen.source_name, '/');
322 if (cpt == NULL)
323 cpt = p_env->gen.source_name;
324 else
325 cpt++;
326 ret = cdio_decode_btl_solaris(cpt, &bus_no, &target_no, &lun_no, 0);
327 if (ret <= 0)
328 return(ret);
329 host_no = bus_no;
330 channel_no = 0;
331 snprintf(tuple, sizeof(tuple)-1, "%d,%d,%d,%d,%d",
332 bus_no, host_no, channel_no, target_no, lun_no);
333 p_env->gen.scsi_tuple = strdup(tuple);
334 return 1;
335 }
336
337 /*!
338 Initialize CD device.
339 */
340 static bool
init_solaris(_img_private_t * p_env)341 init_solaris (_img_private_t *p_env)
342 {
343 int open_flags = O_RDONLY | O_NDELAY;
344
345 if (_AM_MMC_RDWR != p_env->access_mode &&
346 _AM_MMC_RDWR_EXCL != p_env->access_mode)
347 /* (was once set to _AM_SUN_CTRL_SCSI unconditionally) */
348 p_env->access_mode = _AM_SUN_CTRL_SCSI;
349
350 if (!cdio_generic_init(p_env, open_flags))
351 return false;
352 set_scsi_tuple_solaris(p_env);
353 return true;
354 }
355
356 /*!
357 Run a SCSI MMC command.
358
359 p_user_data internal CD structure.
360 i_timeout_ms time in milliseconds we will wait for the command
361 to complete.
362 i_cdb Size of p_cdb
363 p_cdb CDB bytes.
364 e_direction direction the transfer is to go.
365 i_buf Size of buffer
366 p_buf Buffer for data, both sending and receiving
367 */
368 static driver_return_code_t
run_mmc_cmd_solaris(void * p_user_data,unsigned int i_timeout_ms,unsigned int i_cdb,const mmc_cdb_t * p_cdb,cdio_mmc_direction_t e_direction,unsigned int i_buf,void * p_buf)369 run_mmc_cmd_solaris(void *p_user_data, unsigned int i_timeout_ms,
370 unsigned int i_cdb, const mmc_cdb_t *p_cdb,
371 cdio_mmc_direction_t e_direction,
372 unsigned int i_buf, /*in/out*/ void *p_buf)
373 {
374 _img_private_t *p_env = p_user_data;
375 struct uscsi_cmd cgc;
376 int i_rc;
377 cdio_mmc_request_sense_t sense;
378 unsigned char *u_sense = (unsigned char *) &sense;
379
380 memset (&cgc, 0, sizeof (struct uscsi_cmd));
381 cgc.uscsi_cdb = (caddr_t) p_cdb;
382
383 /* See: man uscsi
384 http://docs.sun.com/app/docs/doc/816-5177/uscsi-7i?a=view
385 */
386 p_env->gen.scsi_mmc_sense_valid = 0;
387 memset(u_sense, 0, sizeof(sense));
388 cgc.uscsi_rqbuf = (caddr_t) u_sense;
389 cgc.uscsi_rqlen = sizeof(sense);
390
391 /* No error messages, no retries, do not execute with other commands,
392 request sense data
393 */
394 cgc.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_ISOLATE
395 | USCSI_RQENABLE;
396
397 if (SCSI_MMC_DATA_READ == e_direction)
398 cgc.uscsi_flags |= USCSI_READ;
399 else if (SCSI_MMC_DATA_WRITE == e_direction)
400 cgc.uscsi_flags |= USCSI_WRITE;
401 cgc.uscsi_timeout = msecs2secs(i_timeout_ms);
402 cgc.uscsi_bufaddr = p_buf;
403 cgc.uscsi_buflen = i_buf;
404 cgc.uscsi_cdblen = i_cdb;
405
406 i_rc = ioctl(p_env->gen.fd, USCSICMD, &cgc);
407
408 /* Record SCSI sense reply for API call mmc_last_cmd_sense().
409 */
410 if (sense.additional_sense_len) { /* sense data available */
411 int sense_size = sense.additional_sense_len + 8;
412
413 if (sense_size > sizeof(sense))
414 sense_size = sizeof(sense);
415 memcpy((void *) p_env->gen.scsi_mmc_sense, &sense, sense_size);
416 p_env->gen.scsi_mmc_sense_valid = sense_size;
417 }
418
419 if (0 == i_rc) return DRIVER_OP_SUCCESS;
420 if (-1 == i_rc) {
421 cdio_info ("ioctl USCSICMD failed: %s", strerror(errno));
422 switch (errno) {
423 case EPERM:
424 return DRIVER_OP_NOT_PERMITTED;
425 break;
426 case EINVAL:
427 return DRIVER_OP_BAD_PARAMETER;
428 break;
429 case EFAULT:
430 return DRIVER_OP_BAD_POINTER;
431 break;
432 case EIO:
433 default:
434 return DRIVER_OP_ERROR;
435 break;
436 }
437 }
438 else if (i_rc < -1)
439 return DRIVER_OP_ERROR;
440 else
441 /*Not sure if this the best thing, but we'll use anyway. */
442 return DRIVER_OP_SUCCESS;
443 }
444
445 /*!
446 Reads audio sectors from CD device into data starting from lsn.
447 Returns 0 if no error.
448
449 May have to check size of nblocks. There may be a limit that
450 can be read in one go, e.g. 25 blocks.
451 */
452
453 static int
_read_audio_sectors_solaris(void * p_user_data,void * data,lsn_t i_lsn,unsigned int i_blocks)454 _read_audio_sectors_solaris (void *p_user_data, void *data, lsn_t i_lsn,
455 unsigned int i_blocks)
456 {
457 msf_t _msf;
458 struct cdrom_cdda cdda;
459
460 _img_private_t *p_env = p_user_data;
461
462 cdio_lba_to_msf (cdio_lsn_to_lba(i_lsn), &_msf);
463
464 if (p_env->gen.ioctls_debugged == 75)
465 cdio_debug ("only displaying every 75th ioctl from now on");
466
467 if (p_env->gen.ioctls_debugged == 30 * 75)
468 cdio_debug ("only displaying every 30*75th ioctl from now on");
469
470 if (p_env->gen.ioctls_debugged < 75
471 || (p_env->gen.ioctls_debugged < (30 * 75)
472 && p_env->gen.ioctls_debugged % 75 == 0)
473 || p_env->gen.ioctls_debugged % (30 * 75) == 0)
474 cdio_debug ("reading %d", i_lsn);
475
476 p_env->gen.ioctls_debugged++;
477
478 if (i_blocks > 60) {
479 cdio_warn("%s:\n",
480 "we can't handle reading more than 60 blocks. Reset to 60");
481 }
482
483 cdda.cdda_addr = i_lsn;
484 cdda.cdda_length = i_blocks;
485 cdda.cdda_data = (caddr_t) data;
486 cdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
487
488 if (ioctl (p_env->gen.fd, CDROMCDDA, &cdda) == -1) {
489 perror ("ioctl(..,CDROMCDDA,..)");
490 return DRIVER_OP_ERROR;
491 /* exit (EXIT_FAILURE); */
492 }
493
494 return DRIVER_OP_SUCCESS;
495 }
496
497 /*!
498 Reads a single mode1 sector from cd device into data starting
499 from i_lsn.
500 */
501 static driver_return_code_t
_read_mode1_sector_solaris(void * p_env,void * data,lsn_t i_lsn,bool b_form2)502 _read_mode1_sector_solaris (void *p_env, void *data, lsn_t i_lsn,
503 bool b_form2)
504 {
505
506 #ifdef FIXED
507 do something here.
508 #else
509 return cdio_generic_read_form1_sector(p_env, data, i_lsn);
510 #endif
511 }
512
513 /*!
514 Reads i_blocks of mode2 sectors from cd device into data starting
515 from i_lsn.
516 */
517 static driver_return_code_t
_read_mode1_sectors_solaris(void * p_user_data,void * p_data,lsn_t i_lsn,bool b_form2,unsigned int i_blocks)518 _read_mode1_sectors_solaris (void *p_user_data, void *p_data, lsn_t i_lsn,
519 bool b_form2, unsigned int i_blocks)
520 {
521 _img_private_t *p_env = p_user_data;
522 unsigned int i;
523 int retval;
524 unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
525
526 for (i = 0; i < i_blocks; i++) {
527 if ( (retval = _read_mode1_sector_solaris (p_env,
528 ((char *)p_data) + (blocksize * i),
529 i_lsn + i, b_form2)) )
530 return retval;
531 }
532 return DRIVER_OP_SUCCESS;
533 }
534
535 /*!
536 Reads a single mode2 sector from cd device into data starting from lsn.
537 */
538 static driver_return_code_t
_read_mode2_sector_solaris(void * p_user_data,void * p_data,lsn_t i_lsn,bool b_form2)539 _read_mode2_sector_solaris (void *p_user_data, void *p_data, lsn_t i_lsn,
540 bool b_form2)
541 {
542 char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
543 struct cdrom_msf solaris_msf;
544 msf_t _msf;
545 int offset = 0;
546 struct cdrom_cdxa cd_read;
547
548 _img_private_t *p_env = p_user_data;
549
550 cdio_lba_to_msf (cdio_lsn_to_lba(i_lsn), &_msf);
551 solaris_msf.cdmsf_min0 = cdio_from_bcd8(_msf.m);
552 solaris_msf.cdmsf_sec0 = cdio_from_bcd8(_msf.s);
553 solaris_msf.cdmsf_frame0 = cdio_from_bcd8(_msf.f);
554
555 if (p_env->gen.ioctls_debugged == 75)
556 cdio_debug ("only displaying every 75th ioctl from now on");
557
558 if (p_env->gen.ioctls_debugged == 30 * 75)
559 cdio_debug ("only displaying every 30*75th ioctl from now on");
560
561 if (p_env->gen.ioctls_debugged < 75
562 || (p_env->gen.ioctls_debugged < (30 * 75)
563 && p_env->gen.ioctls_debugged % 75 == 0)
564 || p_env->gen.ioctls_debugged % (30 * 75) == 0)
565 cdio_debug ("reading %2.2d:%2.2d:%2.2d",
566 solaris_msf.cdmsf_min0, solaris_msf.cdmsf_sec0,
567 solaris_msf.cdmsf_frame0);
568
569 p_env->gen.ioctls_debugged++;
570
571 /* Using CDROMXA ioctl will actually use the same uscsi command
572 * as ATAPI, except we don't need to be root
573 */
574 offset = CDIO_CD_XA_SYNC_HEADER;
575 cd_read.cdxa_addr = i_lsn;
576 cd_read.cdxa_data = buf;
577 cd_read.cdxa_length = 1;
578 cd_read.cdxa_format = CDROM_XA_SECTOR_DATA;
579 if (ioctl (p_env->gen.fd, CDROMCDXA, &cd_read) == -1) {
580 perror ("ioctl(..,CDROMCDXA,..)");
581 return 1;
582 /* exit (EXIT_FAILURE); */
583 }
584
585 if (b_form2)
586 memcpy (p_data, buf + (offset-CDIO_CD_SUBHEADER_SIZE), M2RAW_SECTOR_SIZE);
587 else
588 memcpy (((char *)p_data), buf + offset, CDIO_CD_FRAMESIZE);
589
590 return DRIVER_OP_SUCCESS;
591 }
592
593 /*!
594 Reads i_blocks of mode2 sectors from cd device into data starting
595 from i_lsn.
596 */
597 static driver_return_code_t
_read_mode2_sectors_solaris(void * p_user_data,void * data,lsn_t i_lsn,bool b_form2,unsigned int i_blocks)598 _read_mode2_sectors_solaris (void *p_user_data, void *data, lsn_t i_lsn,
599 bool b_form2, unsigned int i_blocks)
600 {
601 _img_private_t *p_env = p_user_data;
602 unsigned int i;
603 int retval;
604 unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
605
606 for (i = 0; i < i_blocks; i++) {
607 if ( (retval = _read_mode2_sector_solaris (p_env,
608 ((char *)data) + (blocksize * i),
609 i_lsn + i, b_form2)) )
610 return retval;
611 }
612 return 0;
613 }
614
615
616 /*!
617 Return the size of the CD in logical block address (LBA) units.
618 @return the size. On error return CDIO_INVALID_LSN.
619 */
620 static lsn_t
get_disc_last_lsn_solaris(void * p_user_data)621 get_disc_last_lsn_solaris (void *p_user_data)
622 {
623 _img_private_t *p_env = p_user_data;
624
625 struct cdrom_tocentry tocent;
626 uint32_t size;
627
628 tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK;
629 tocent.cdte_format = CDIO_CDROM_LBA;
630 if (ioctl (p_env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
631 {
632 perror ("ioctl(CDROMREADTOCENTRY)");
633 exit (EXIT_FAILURE);
634 }
635
636 size = tocent.cdte_addr.lba;
637
638 return size;
639 }
640
641 /*!
642 Set the arg "key" with "value" in the source device.
643 Currently "source" and "access-mode" are valid keys.
644 "source" sets the source device in I/O operations
645 "access-mode" sets the the method of CD access
646
647 DRIVER_OP_SUCCESS is returned if no error was found,
648 and nonzero if there as an error.
649 */
650 static driver_return_code_t
_set_arg_solaris(void * p_user_data,const char key[],const char value[])651 _set_arg_solaris (void *p_user_data, const char key[], const char value[])
652 {
653 _img_private_t *p_env = p_user_data;
654
655 if (!strcmp (key, "source"))
656 {
657 if (!value) return DRIVER_OP_ERROR;
658 free (p_env->gen.source_name);
659 p_env->gen.source_name = strdup (value);
660 }
661 else if (!strcmp (key, "access-mode"))
662 {
663 p_env->access_mode = str_to_access_mode_solaris(key);
664 }
665 else return DRIVER_OP_ERROR;
666
667 return DRIVER_OP_SUCCESS;
668 }
669
670 /*!
671 Read and cache the CD's Track Table of Contents and track info.
672 Return true if successful or false if an error.
673 */
674 static bool
read_toc_solaris(void * p_user_data)675 read_toc_solaris (void *p_user_data)
676 {
677 _img_private_t *p_env = p_user_data;
678 int i;
679
680 /* read TOC header */
681 if ( ioctl(p_env->gen.fd, CDROMREADTOCHDR, &p_env->tochdr) == -1 ) {
682 cdio_warn("%s: %s\n",
683 "error in ioctl CDROMREADTOCHDR", strerror(errno));
684 return false;
685 }
686
687 p_env->gen.i_first_track = p_env->tochdr.cdth_trk0;
688 p_env->gen.i_tracks = p_env->tochdr.cdth_trk1;
689
690 /* read individual tracks */
691 for (i=p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++) {
692 struct cdrom_tocentry *p_toc =
693 &(p_env->tocent[i-p_env->gen.i_first_track]);
694
695 p_toc->cdte_track = i;
696 p_toc->cdte_format = CDIO_CDROM_MSF;
697 if ( ioctl(p_env->gen.fd, CDROMREADTOCENTRY, p_toc) == -1 ) {
698 cdio_warn("%s %d: %s\n",
699 "error in ioctl CDROMREADTOCENTRY for track",
700 i, strerror(errno));
701 return false;
702 }
703
704 set_track_flags(&(p_env->gen.track_flags[i]), p_toc->cdte_ctrl);
705 }
706
707 /* read the lead-out track */
708 p_env->tocent[p_env->tochdr.cdth_trk1].cdte_track = CDIO_CDROM_LEADOUT_TRACK;
709 p_env->tocent[p_env->tochdr.cdth_trk1].cdte_format = CDIO_CDROM_MSF;
710
711 if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY,
712 &p_env->tocent[p_env->tochdr.cdth_trk1]) == -1 ) {
713 cdio_warn("%s: %s\n",
714 "error in ioctl CDROMREADTOCENTRY for lead-out",
715 strerror(errno));
716 return false;
717 }
718
719 p_env->gen.toc_init = true;
720 return true;
721 }
722
723 /*!
724 Eject media in CD drive. If successful, as a side effect we
725 also free obj.
726 */
727 static driver_return_code_t
eject_media_solaris(void * p_user_data)728 eject_media_solaris (void *p_user_data) {
729
730 _img_private_t *p_env = p_user_data;
731 int ret;
732
733 close(p_env->gen.fd);
734 p_env->gen.fd = -1;
735 if (p_env->gen.fd > -1) {
736 if ((ret = ioctl(p_env->gen.fd, CDROMEJECT)) != 0) {
737 cdio_generic_free((void *) p_env);
738 cdio_warn ("CDROMEJECT failed: %s\n", strerror(errno));
739 return DRIVER_OP_ERROR;
740 } else {
741 return DRIVER_OP_SUCCESS;
742 }
743 }
744 return DRIVER_OP_ERROR;
745 }
746
747 static bool
is_mmc_supported(void * user_data)748 is_mmc_supported(void *user_data)
749 {
750 _img_private_t *env = user_data;
751 return (_AM_NONE == env->access_mode) ? false : true;
752 }
753
754 /*!
755 Return the value associated with the key "arg".
756 */
757 static const char *
get_arg_solaris(void * p_user_data,const char key[])758 get_arg_solaris (void *p_user_data, const char key[])
759 {
760 _img_private_t *p_env = p_user_data;
761
762 if (!strcmp (key, "source")) {
763 return p_env->gen.source_name;
764 } else if (!strcmp (key, "access-mode")) {
765 switch (p_env->access_mode) {
766 case _AM_SUN_CTRL_ATAPI:
767 return "ATAPI";
768 case _AM_SUN_CTRL_SCSI:
769 return "SCSI";
770 case _AM_MMC_RDWR:
771 return "MMC_RDWR";
772 case _AM_MMC_RDWR_EXCL:
773 return "MMC_RDWR_EXCL";
774 case _AM_NONE:
775 return "no access method";
776 }
777 } else if (!strcmp (key, "scsi-tuple")) {
778 return p_env->gen.scsi_tuple;
779 } else if (!strcmp (key, "mmc-supported?")) {
780 return is_mmc_supported(p_user_data) ? "true" : "false";
781 }
782 return NULL;
783 }
784
785 /*!
786 Get the block size used in read requests, via ioctl.
787 @return the blocksize if > 0; error if <= 0
788 */
789 static int
get_blocksize_solaris(void * p_user_data)790 get_blocksize_solaris (void *p_user_data) {
791
792 _img_private_t *p_env = p_user_data;
793 int ret;
794 int i_blocksize;
795
796 if ( !p_env || p_env->gen.fd <=0 ) return DRIVER_OP_UNINIT;
797 if ((ret = ioctl(p_env->gen.fd, CDROMGBLKMODE, &i_blocksize)) != 0) {
798 cdio_warn ("CDROMGBLKMODE failed: %s\n", strerror(errno));
799 return DRIVER_OP_ERROR;
800 } else {
801 return i_blocksize;
802 }
803 }
804
805 #ifdef HAVE_SOLARIS_CDROM
806 /*!
807 Return a string containing the default CD device if none is specified.
808 This call does not assume a fixed default drive address but rather uses
809 the first drive that gets enumerated by cdio_get_devices_solaris_cXtYdZs2().
810 */
811 static char *
cdio_get_default_cXtYdZs2(void)812 cdio_get_default_cXtYdZs2(void)
813 {
814 char **devlist, *result = NULL;
815
816 devlist = cdio_get_devices_solaris_cXtYdZs2(1);
817 if(devlist != NULL) {
818 if(devlist[0] != NULL)
819 result = strdup(devlist[0]);
820 free(devlist);
821 }
822 if(result != NULL)
823 return result;
824 return strdup(DEFAULT_CDIO_DEVICE);
825 }
826 #endif
827
828 /*!
829 Return a string containing the default CD device if none is specified.
830 */
831 char *
cdio_get_default_device_solaris(void)832 cdio_get_default_device_solaris(void)
833 {
834 char *volume_device;
835 char *volume_name;
836 char *volume_action;
837 char *device;
838 struct stat stb;
839
840 /* vold and its directory /vol have been replaced by "Tamarack" which
841 is based on hald. This happened in 2006.
842 */
843 if(stat("/vol", &stb) == -1)
844 return cdio_get_default_cXtYdZs2();
845 if((stb.st_mode & S_IFMT) != S_IFDIR)
846 return cdio_get_default_cXtYdZs2();
847
848 if ((volume_device = getenv("VOLUME_DEVICE")) != NULL &&
849 (volume_name = getenv("VOLUME_NAME")) != NULL &&
850 (volume_action = getenv("VOLUME_ACTION")) != NULL &&
851 strcmp(volume_action, "insert") == 0) {
852 uint len = strlen(volume_device) + strlen(volume_name) + 2;
853 device = calloc(1, len);
854 if (device == NULL)
855 return strdup(DEFAULT_CDIO_DEVICE);
856 snprintf(device, len, "%s/%s", volume_device, volume_name);
857 if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) {
858 free(device);
859 return strdup(DEFAULT_CDIO_DEVICE);
860 }
861 return device;
862 }
863 /* Check if it could be a Solaris media*/
864 if((stat(DEFAULT_CDIO_DEVICE, &stb) == 0) && S_ISDIR(stb.st_mode)) {
865 uint len = strlen(DEFAULT_CDIO_DEVICE + 4);
866 device = calloc(1, len);
867 snprintf(device, len, "%s/s0", DEFAULT_CDIO_DEVICE);
868 return device;
869 }
870 return strdup(DEFAULT_CDIO_DEVICE);
871 }
872
873 /*!
874 Get disc type associated with cd object.
875 */
876
877 static discmode_t
get_discmode_solaris(void * p_user_data)878 get_discmode_solaris (void *p_user_data)
879 {
880 _img_private_t *p_env = p_user_data;
881 track_t i_track;
882 discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
883 struct dk_minfo media;
884 int ret;
885
886 memset(&media, 0, sizeof(media));
887
888 /* Get the media info */
889 if((ret = ioctl(p_env->gen.fd, DKIOCGMEDIAINFO, &media)) != 0) {
890 cdio_warn ("DKIOCGMEDIAINFO failed: %s\n", strerror(errno));
891 return CDIO_DISC_MODE_NO_INFO;
892 }
893 switch(media.dki_media_type) {
894 case DK_CDROM:
895 case DK_CDR:
896 case DK_CDRW:
897 /* Do cdrom detection */
898 break;
899 case DK_DVDROM: return CDIO_DISC_MODE_DVD_ROM;
900 case DK_DVDR: discmode = CDIO_DISC_MODE_DVD_R;
901 break;
902 case DK_DVDRAM: discmode = CDIO_DISC_MODE_DVD_RAM;
903 break;
904 case DK_DVDRW:
905 case DK_DVDRW+1: discmode = CDIO_DISC_MODE_DVD_RW;
906 break;
907 default: /* no valid match */
908 return CDIO_DISC_MODE_NO_INFO;
909 }
910
911 /*
912 GNU/Linux ioctl(.., CDROM_DISC_STATUS) does not return "CD DATA
913 Form 2" for SVCD's even though they are are form 2.
914 Issue a SCSI MMC-2 FULL TOC command first to try get more
915 accurate information.
916 */
917 discmode = mmc_get_discmode(p_env->gen.cdio);
918 if (CDIO_DISC_MODE_NO_INFO != discmode)
919 return discmode;
920
921 if((discmode == CDIO_DISC_MODE_DVD_RAM ||
922 discmode == CDIO_DISC_MODE_DVD_RW ||
923 discmode == CDIO_DISC_MODE_DVD_R)) {
924 /* Fallback to uscsi if we can */
925 if(geteuid() == 0)
926 return get_discmode_solaris(p_user_data);
927 return discmode;
928 }
929
930 if (!p_env->gen.toc_init)
931 read_toc_solaris (p_env);
932
933 if (!p_env->gen.toc_init)
934 return CDIO_DISC_MODE_NO_INFO;
935
936 for (i_track = p_env->gen.i_first_track;
937 i_track < p_env->gen.i_first_track + p_env->tochdr.cdth_trk1 ;
938 i_track ++) {
939 track_format_t track_fmt=get_track_format_solaris(p_env, i_track);
940
941 switch(track_fmt) {
942 case TRACK_FORMAT_AUDIO:
943 switch(discmode) {
944 case CDIO_DISC_MODE_NO_INFO:
945 discmode = CDIO_DISC_MODE_CD_DA;
946 break;
947 case CDIO_DISC_MODE_CD_DA:
948 case CDIO_DISC_MODE_CD_MIXED:
949 case CDIO_DISC_MODE_ERROR:
950 /* No change*/
951 break;
952 default:
953 discmode = CDIO_DISC_MODE_CD_MIXED;
954 }
955 break;
956 case TRACK_FORMAT_XA:
957 switch(discmode) {
958 case CDIO_DISC_MODE_NO_INFO:
959 discmode = CDIO_DISC_MODE_CD_XA;
960 break;
961 case CDIO_DISC_MODE_CD_XA:
962 case CDIO_DISC_MODE_CD_MIXED:
963 case CDIO_DISC_MODE_ERROR:
964 /* No change*/
965 break;
966 default:
967 discmode = CDIO_DISC_MODE_CD_MIXED;
968 }
969 break;
970 case TRACK_FORMAT_DATA:
971 switch(discmode) {
972 case CDIO_DISC_MODE_NO_INFO:
973 discmode = CDIO_DISC_MODE_CD_DATA;
974 break;
975 case CDIO_DISC_MODE_CD_DATA:
976 case CDIO_DISC_MODE_CD_MIXED:
977 case CDIO_DISC_MODE_ERROR:
978 /* No change*/
979 break;
980 default:
981 discmode = CDIO_DISC_MODE_CD_MIXED;
982 }
983 break;
984 case TRACK_FORMAT_ERROR:
985 default:
986 discmode = CDIO_DISC_MODE_ERROR;
987 }
988 }
989 return discmode;
990 }
991
992 /*!
993 Return the session number of the last on the CD.
994
995 @param p_cdio the CD object to be acted upon.
996 @param i_last_session pointer to the session number to be returned.
997 */
998 static driver_return_code_t
get_last_session_solaris(void * p_user_data,lsn_t * i_last_session_lsn)999 get_last_session_solaris (void *p_user_data,
1000 /*out*/ lsn_t *i_last_session_lsn)
1001 {
1002 const _img_private_t *p_env = p_user_data;
1003 int i_rc;
1004
1005 i_rc = ioctl(p_env->gen.fd, CDROMREADOFFSET, &i_last_session_lsn);
1006 if (0 == i_rc) {
1007 return DRIVER_OP_SUCCESS;
1008 } else {
1009 cdio_warn ("ioctl CDROMREADOFFSET failed: %s\n", strerror(errno));
1010 return DRIVER_OP_ERROR;
1011 }
1012 }
1013
1014 /*!
1015 Get format of track.
1016 */
1017 static track_format_t
get_track_format_solaris(void * p_user_data,track_t i_track)1018 get_track_format_solaris(void *p_user_data, track_t i_track)
1019 {
1020 _img_private_t *p_env = p_user_data;
1021
1022 if ( !p_env ) return TRACK_FORMAT_ERROR;
1023 if (!p_env->gen.init) init_solaris(p_env);
1024 if (!p_env->gen.toc_init) read_toc_solaris (p_user_data) ;
1025
1026 if ( (i_track > p_env->gen.i_tracks+p_env->gen.i_first_track)
1027 || i_track < p_env->gen.i_first_track)
1028 return TRACK_FORMAT_ERROR;
1029
1030 i_track -= p_env->gen.i_first_track;
1031
1032 /* This is pretty much copied from the "badly broken" cdrom_count_tracks
1033 in linux/cdrom.c.
1034 */
1035 if (p_env->tocent[i_track].cdte_ctrl & CDROM_DATA_TRACK) {
1036 if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK)
1037 return TRACK_FORMAT_CDI;
1038 else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK)
1039 return TRACK_FORMAT_XA;
1040 else
1041 return TRACK_FORMAT_DATA;
1042 } else
1043 return TRACK_FORMAT_AUDIO;
1044
1045 }
1046
1047 /*!
1048 Return true if we have XA data (green, mode2 form1) or
1049 XA data (green, mode2 form2). That is track begins:
1050 sync - header - subheader
1051 12 4 - 8
1052
1053 FIXME: there's gotta be a better design for this and get_track_format?
1054 */
1055 static bool
get_track_green_solaris(void * p_user_data,track_t i_track)1056 get_track_green_solaris(void *p_user_data, track_t i_track)
1057 {
1058 _img_private_t *p_env = p_user_data;
1059
1060 if ( !p_env ) return false;
1061 if (!p_env->gen.init) init_solaris(p_env);
1062 if (!p_env->gen.toc_init) read_toc_solaris (p_env) ;
1063
1064 if (i_track >= p_env->gen.i_tracks+p_env->gen.i_first_track
1065 || i_track < p_env->gen.i_first_track)
1066 return false;
1067
1068 i_track -= p_env->gen.i_first_track;
1069
1070 /* FIXME: Dunno if this is the right way, but it's what
1071 I was using in cd-info for a while.
1072 */
1073 return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0);
1074 }
1075
1076 /*!
1077 Return the starting MSF (minutes/secs/frames) for track number
1078 track_num in obj. Track numbers usually start at something
1079 greater than 0, usually 1.
1080
1081 The "leadout" track is specified either by
1082 using track_num LEADOUT_TRACK or the total tracks+1.
1083 False is returned if there is no entry.
1084 */
1085 static bool
get_track_msf_solaris(void * p_user_data,track_t i_track,msf_t * msf)1086 get_track_msf_solaris(void *p_user_data, track_t i_track, msf_t *msf)
1087 {
1088 _img_private_t *p_env = p_user_data;
1089
1090 if (NULL == msf) return false;
1091
1092 if (!p_env->gen.init) init_solaris(p_env);
1093 if (!p_env->gen.toc_init) read_toc_solaris (p_env) ;
1094
1095 if (i_track == CDIO_CDROM_LEADOUT_TRACK)
1096 i_track = p_env->gen.i_tracks + p_env->gen.i_first_track;
1097
1098 if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track)
1099 || i_track < p_env->gen.i_first_track) {
1100 return false;
1101 } else {
1102 struct cdrom_tocentry *msf0 = &p_env->tocent[i_track-1];
1103 msf->m = cdio_to_bcd8(msf0->cdte_addr.msf.minute);
1104 msf->s = cdio_to_bcd8(msf0->cdte_addr.msf.second);
1105 msf->f = cdio_to_bcd8(msf0->cdte_addr.msf.frame);
1106 return true;
1107 }
1108 }
1109
1110 /*!
1111 Get the block size used in read requests, via ioctl.
1112 @return the blocksize if > 0; error if <= 0
1113 */
1114 static driver_return_code_t
set_blocksize_solaris(void * p_user_data,uint16_t i_blocksize)1115 set_blocksize_solaris (void *p_user_data, uint16_t i_blocksize) {
1116
1117 _img_private_t *p_env = p_user_data;
1118 int ret;
1119
1120 if ( !p_env || p_env->gen.fd <=0 ) return DRIVER_OP_UNINIT;
1121 if ((ret = ioctl(p_env->gen.fd, CDROMSBLKMODE, i_blocksize)) != 0) {
1122 cdio_warn ("CDROMSBLKMODE failed: %s\n", strerror(errno));
1123 return DRIVER_OP_ERROR;
1124 } else {
1125 return DRIVER_OP_SUCCESS;
1126 }
1127 }
1128
1129 /* Set CD-ROM drive speed */
1130 static driver_return_code_t
set_speed_solaris(void * p_user_data,int i_speed)1131 set_speed_solaris (void *p_user_data, int i_speed)
1132 {
1133 const _img_private_t *p_env = p_user_data;
1134
1135 if (!p_env) return DRIVER_OP_UNINIT;
1136 return ioctl(p_env->gen.fd, CDROMSDRVSPEED, i_speed);
1137 }
1138
1139 #else
1140 /*!
1141 Return a string containing the default VCD device if none is specified.
1142 */
1143 char *
cdio_get_default_device_solaris(void)1144 cdio_get_default_device_solaris(void)
1145 {
1146 return strdup(DEFAULT_CDIO_DEVICE);
1147 }
1148
1149 #endif /* HAVE_SOLARIS_CDROM */
1150
1151 /*!
1152 Close tray on CD-ROM.
1153
1154 @param psz_device the CD-ROM drive to be closed.
1155
1156 */
1157 driver_return_code_t
close_tray_solaris(const char * psz_device)1158 close_tray_solaris (const char *psz_device)
1159 {
1160 #ifdef HAVE_SOLARIS_CDROM
1161 int i_rc;
1162 int fd = open (psz_device, O_RDONLY|O_NONBLOCK);
1163
1164 if ( fd > -1 ) {
1165 i_rc = DRIVER_OP_SUCCESS;
1166 if((i_rc = ioctl(fd, CDROMSTART)) != 0) {
1167 cdio_warn ("ioctl CDROMSTART failed: %s\n", strerror(errno));
1168 i_rc = DRIVER_OP_ERROR;
1169 }
1170 close(fd);
1171 } else
1172 i_rc = DRIVER_OP_ERROR;
1173 return i_rc;
1174 #else
1175 return DRIVER_OP_NO_DRIVER;
1176 #endif /*HAVE_SOLARIS_CDROM*/
1177 }
1178
1179 #ifdef HAVE_SOLARIS_CDROM
1180 /*!
1181 Return an array of strings giving possible CD devices.
1182 New method after demise of vold in 2006.
1183 */
1184 /* flag bit0= need only the first drive
1185 */
1186 static char **
cdio_get_devices_solaris_cXtYdZs2(int flag)1187 cdio_get_devices_solaris_cXtYdZs2(int flag)
1188 {
1189 int busno, tgtno, lunno, ret;
1190 char volpath[160];
1191 char **drives = NULL;
1192 unsigned int i_files=0;
1193 DIR *dir = NULL;
1194 struct dirent *entry;
1195
1196 #ifdef LIBCDIO_SOLARIS_WITH_CD_INQUIRY
1197 CdIo_t *cdio = NULL;
1198 mmc_cdb_t cdb = {{0, }};
1199 int timeout_ms;
1200 driver_return_code_t i_status;
1201 char reply[36];
1202 static unsigned char spc_inquiry[] = { 0x12, 0, 0, 0, 36, 0 };
1203 #else
1204 struct dk_cinfo cinfo;
1205 int fd = -1;
1206 #endif
1207
1208 static int recursion = 0;
1209
1210 if (recursion) {
1211 fprintf(stderr, "Program error ! Recursion of cdio_get_devices_solaris_cXtYdZs2()\n");
1212 return NULL;
1213 }
1214 recursion = 1;
1215
1216 dir = opendir("/dev/rdsk");
1217 if (dir == NULL) {
1218 cdio_warn ("opendir(\"/dev/rdsk\") failed: %s\n", strerror(errno));
1219 goto ex;
1220 }
1221 while (1) {
1222 entry = readdir(dir);
1223 if (entry == NULL) {
1224 if (errno) {
1225 cdio_warn ("readdir(/dev/rdsk) failed: %s\n", strerror(errno));
1226 goto ex;
1227 }
1228 break;
1229 }
1230 ret = cdio_decode_btl_solaris(entry->d_name, &busno, &tgtno, &lunno, 0);
1231 if (ret < 0)
1232 goto ex;
1233 if (ret == 0)
1234 continue; /* not cXtYdZs2 */
1235
1236 if (strlen(entry->d_name) > sizeof(volpath) - 11)
1237 continue;
1238 snprintf(volpath, sizeof(volpath), "/dev/rdsk/%s", entry->d_name);
1239
1240 #ifdef LIBCDIO_SOLARIS_WITH_CD_INQUIRY
1241
1242 cdio = cdio_open_am_solaris(volpath, "MMC_RDWR");
1243 if(cdio == NULL)
1244 continue;
1245 memcpy(cdb.field, spc_inquiry, 6);
1246 timeout_ms = 10000;
1247 i_status = run_mmc_cmd_solaris(cdio->env, timeout_ms,
1248 6, &cdb, SCSI_MMC_DATA_READ,
1249 (unsigned int) spc_inquiry[4], reply);
1250 cdio_destroy(cdio);
1251 cdio = NULL;
1252 if (i_status != 0)
1253 continue;
1254
1255 /* SBC-3 , table 83 , PERIPHERAL DEVICE TYPE : 5 = CD/DVD device */
1256 if((reply[0] & 0x1F) != 5)
1257 continue;
1258
1259 #else /* LIBCDIO_SOLARIS_WITH_CD_INQUIRY */
1260
1261 fd = open(volpath, O_RDONLY | O_NDELAY);
1262 if (fd < 0)
1263 continue;
1264 /* See man dkio */
1265 ret = ioctl(fd, DKIOCINFO, &cinfo);
1266 close(fd);
1267 fd = -1;
1268 if (ret < 0)
1269 continue;
1270 if (cinfo.dki_ctype != DKC_CDROM)
1271 continue;
1272
1273 #endif /* ! LIBCDIO_SOLARIS_WITH_CD_INQUIRY */
1274
1275 cdio_add_device_list(&drives, volpath, &i_files);
1276 if(flag & 1)
1277 goto ex; /* Only the first drive is desired */
1278 }
1279 ex:;
1280 recursion = 0;
1281 if(dir != NULL)
1282 closedir(dir);
1283 cdio_add_device_list(&drives, NULL, &i_files);
1284 return drives;
1285 }
1286 #endif /*HAVE_SOLARIS_CDROM*/
1287
1288 /*!
1289 Return an array of strings giving possible CD devices.
1290 */
1291 char **
cdio_get_devices_solaris(void)1292 cdio_get_devices_solaris (void)
1293 {
1294 #ifndef HAVE_SOLARIS_CDROM
1295 return NULL;
1296 #else
1297 char volpath[256];
1298 struct stat st;
1299 char **drives = NULL;
1300 unsigned int i_files=0;
1301 #ifdef HAVE_GLOB_H
1302 unsigned int i;
1303 glob_t globbuf;
1304 #endif
1305
1306 /* vold and its directory /vol have been replaced by "Tamarack" which
1307 is based on hald. This happened in 2006.
1308 */
1309 if(stat("/vol", &st) == -1)
1310 return cdio_get_devices_solaris_cXtYdZs2(0);
1311 if((st.st_mode & S_IFMT) != S_IFDIR)
1312 return cdio_get_devices_solaris_cXtYdZs2(0);
1313
1314 #ifdef HAVE_GLOB_H
1315
1316 globbuf.gl_offs = 0;
1317 glob("/vol/dev/aliases/cdrom*", GLOB_DOOFFS, NULL, &globbuf);
1318 for (i=0; i<globbuf.gl_pathc; i++) {
1319 if(stat(globbuf.gl_pathv[i], &st) < 0)
1320 continue;
1321
1322 /* Check if this is a directory, if so it's probably Solaris media */
1323 if(S_ISDIR(st.st_mode)) {
1324 snprintf(volpath, sizeof(volpath), "%s/s0", globbuf.gl_pathv[i]);
1325 if(stat(volpath, &st) == 0)
1326 cdio_add_device_list(&drives, volpath, &i_files);
1327 }else
1328 cdio_add_device_list(&drives, globbuf.gl_pathv[i], &i_files);
1329 }
1330 globfree(&globbuf);
1331 #else
1332 if(stat(DEFAULT_CDIO_DEVICE, &st) == 0) {
1333 /* Check if this is a directory, if so it's probably Solaris media */
1334 if(S_ISDIR(st.st_mode)) {
1335 snprintf(volpath, sizeof(volpath), "%s/s0", DEFAULT_CDIO_DEVICE);
1336 if(stat(volpath, &st) == 0)
1337 cdio_add_device_list(&drives, volpath, &i_files);
1338 }else
1339 cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &i_files);
1340 }
1341 #endif /*HAVE_GLOB_H*/
1342 cdio_add_device_list(&drives, NULL, &i_files);
1343 return drives;
1344 #endif /*HAVE_SOLARIS_CDROM*/
1345 }
1346
1347 /*!
1348 Initialization routine. This is the only thing that doesn't
1349 get called via a function pointer. In fact *we* are the
1350 ones to set that up.
1351 */
1352 CdIo *
cdio_open_solaris(const char * psz_source_name)1353 cdio_open_solaris (const char *psz_source_name)
1354 {
1355 return cdio_open_am_solaris(psz_source_name, NULL);
1356 }
1357
1358 /*!
1359 Initialization routine. This is the only thing that doesn't
1360 get called via a function pointer. In fact *we* are the
1361 ones to set that up.
1362 */
1363 CdIo *
cdio_open_am_solaris(const char * psz_orig_source,const char * access_mode)1364 cdio_open_am_solaris (const char *psz_orig_source, const char *access_mode)
1365 {
1366
1367 #ifdef HAVE_SOLARIS_CDROM
1368 CdIo *ret;
1369 _img_private_t *_data;
1370 char *psz_source;
1371
1372 cdio_funcs_t _funcs;
1373
1374 memset(&_funcs, 0, sizeof(_funcs));
1375
1376 _funcs.audio_pause = audio_pause_solaris;
1377 _funcs.audio_play_msf = audio_play_msf_solaris;
1378 _funcs.audio_play_track_index = audio_play_track_index_solaris;
1379 _funcs.audio_read_subchannel = audio_read_subchannel_solaris;
1380 _funcs.audio_resume = audio_resume_solaris;
1381 _funcs.audio_set_volume = audio_set_volume_solaris;
1382 _funcs.audio_stop = audio_stop_solaris,
1383 _funcs.eject_media = eject_media_solaris;
1384 _funcs.free = cdio_generic_free;
1385 _funcs.get_arg = get_arg_solaris;
1386 #ifdef USE_MMC
1387 _funcs.get_blocksize = get_blocksize_mmc;
1388 #else
1389 _funcs.get_blocksize = get_blocksize_solaris;
1390 #endif
1391 _funcs.get_cdtext = get_cdtext_generic;
1392 _funcs.get_cdtext_raw = read_cdtext_generic;
1393 _funcs.get_default_device = cdio_get_default_device_solaris;
1394 _funcs.get_devices = cdio_get_devices_solaris;
1395 _funcs.get_disc_last_lsn = get_disc_last_lsn_solaris;
1396 _funcs.get_discmode = get_discmode_solaris;
1397 _funcs.get_drive_cap = get_drive_cap_mmc;
1398 _funcs.get_first_track_num = get_first_track_num_generic;
1399 _funcs.get_hwinfo = NULL;
1400 _funcs.get_last_session = get_last_session_solaris;
1401 _funcs.get_media_changed = get_media_changed_mmc,
1402 _funcs.get_mcn = get_mcn_mmc,
1403 _funcs.get_num_tracks = get_num_tracks_generic;
1404 _funcs.get_track_channels = get_track_channels_generic,
1405 _funcs.get_track_copy_permit = get_track_copy_permit_generic,
1406 _funcs.get_track_format = get_track_format_solaris;
1407 _funcs.get_track_green = get_track_green_solaris;
1408 _funcs.get_track_lba = NULL; /* This could be done if need be. */
1409 _funcs.get_track_preemphasis = get_track_preemphasis_generic,
1410 _funcs.get_track_msf = get_track_msf_solaris;
1411 _funcs.get_track_isrc = get_track_isrc_solaris;
1412 _funcs.lseek = cdio_generic_lseek;
1413 _funcs.read = cdio_generic_read;
1414 _funcs.read_audio_sectors = _read_audio_sectors_solaris;
1415 _funcs.read_data_sectors = read_data_sectors_generic;
1416 _funcs.read_mode1_sector = _read_mode1_sector_solaris;
1417 _funcs.read_mode1_sectors = _read_mode1_sectors_solaris;
1418 _funcs.read_mode2_sector = _read_mode2_sector_solaris;
1419 _funcs.read_mode2_sectors = _read_mode2_sectors_solaris;
1420 _funcs.read_toc = read_toc_solaris;
1421 _funcs.run_mmc_cmd = run_mmc_cmd_solaris;
1422 _funcs.set_arg = _set_arg_solaris;
1423 #ifdef USE_MMC
1424 _funcs.set_blocksize = set_blocksize_mmc;
1425 #else
1426 _funcs.set_blocksize = set_blocksize_solaris;
1427 #endif
1428 _funcs.set_speed = set_speed_solaris;
1429
1430 _data = calloc(1, sizeof (_img_private_t));
1431
1432 _data->access_mode = str_to_access_mode_solaris(access_mode);
1433 _data->gen.init = false;
1434 _data->gen.fd = -1;
1435 _data->gen.toc_init = false;
1436 _data->gen.b_cdtext_error = false;
1437
1438 if (NULL == psz_orig_source) {
1439 psz_source = cdio_get_default_device_solaris();
1440 if (NULL == psz_source) {
1441 free(_data);
1442 return NULL;
1443 }
1444
1445 _set_arg_solaris(_data, "source", psz_source);
1446 free(psz_source);
1447 } else {
1448 if (cdio_is_device_generic(psz_orig_source))
1449 _set_arg_solaris(_data, "source", psz_orig_source);
1450 else {
1451 /* The below would be okay if all device drivers worked this way. */
1452 #if 0
1453 cdio_info ("source %s is not a device", psz_orig_source);
1454 #endif
1455 free(_data);
1456 return NULL;
1457 }
1458 }
1459
1460 ret = cdio_new ( (void *) _data, &_funcs );
1461 if (ret == NULL) return NULL;
1462
1463 ret->driver_id = DRIVER_SOLARIS;
1464
1465 if (init_solaris(_data))
1466 return ret;
1467 else {
1468 cdio_generic_free (_data);
1469 free(ret);
1470 return NULL;
1471 }
1472
1473 #else
1474 return NULL;
1475 #endif /* HAVE_SOLARIS_CDROM */
1476
1477 }
1478
1479 bool
cdio_have_solaris(void)1480 cdio_have_solaris (void)
1481 {
1482 #ifdef HAVE_SOLARIS_CDROM
1483 return true;
1484 #else
1485 return false;
1486 #endif /* HAVE_SOLARIS_CDROM */
1487 }
1488