filename | src/drivers/cdrom/sector.c |
changeset | 1097:d4807997e450 |
next | 1099:566cdeb157ec |
author | nkeynes |
date | Sun Jan 31 18:35:06 2010 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Refactor CDROM host support - Completely separate GDROM hardware (in gdrom/gdrom.c) from generic CDROM support (now in drivers/cdrom) - Add concept of 'sector sources' that can be mixed and matched to create cdrom discs (makes support of arbitrary disc types much simpler) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * low-level 'block device' for input to gdrom discs.
5 *
6 * Copyright (c) 2009 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include <sys/stat.h>
20 #include <glib/gmem.h>
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
28 #include "drivers/cdrom/sector.h"
29 #include "drivers/cdrom/cdrom.h"
30 #include "drivers/cdrom/ecc.h"
32 #define CHECK_READ(dev,lba,count) \
33 if( !IS_SECTOR_SOURCE(dev) ) { \
34 return CDROM_ERROR_NODISC; \
35 } else if( (lba) >= (dev)->size || (lba+block_count) > (dev)->size ) { \
36 return CDROM_ERROR_BADREAD; \
37 }
39 /* Default read mode for each sector mode */
40 const uint32_t cdrom_sector_read_mode[] = { 0,
41 CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
42 CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
43 CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
44 CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
45 CDROM_READ_RAW, CDROM_READ_RAW };
47 /* Block size for each sector mode */
48 const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352 };
50 const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
51 "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
54 /********************* Public functions *************************/
55 cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
56 {
57 CHECK_READ(device,lba,block_count);
58 return device->read_blocks(device, lba, block_count, buf);
59 }
61 cdrom_error_t sector_source_read_sectors( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
62 unsigned char *buf, size_t *length )
63 {
64 CHECK_READ(device,lba,block_count);
65 return device->read_sectors(device, lba, block_count, mode, buf, length);
66 }
68 void sector_source_ref( sector_source_t device )
69 {
70 assert( IS_SECTOR_SOURCE(device) );
71 device->ref_count++;
72 }
74 void sector_source_unref( sector_source_t device )
75 {
76 if( device == NULL )
77 return;
78 assert( IS_SECTOR_SOURCE(device) );
79 if( device->ref_count > 0 )
80 device->ref_count--;
81 if( device->ref_count == 0 )
82 device->destroy(device);
83 }
85 void sector_source_release( sector_source_t device )
86 {
87 assert( IS_SECTOR_SOURCE(device) );
88 if( device->ref_count == 0 )
89 device->destroy(device);
90 }
92 /************************** Sector mangling ***************************/
93 /*
94 * Private functions used to pack/unpack sectors, determine mode, and
95 * evaluate sector reads.
96 */
98 /** Basic data sector header structure */
99 struct cdrom_sector_header {
100 uint8_t sync[12];
101 uint8_t msf[3];
102 uint8_t mode;
103 uint8_t subhead[8]; // Mode-2 XA sectors only
104 };
106 static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
108 /* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
109 static const uint8_t legal_nonxa_fields[] =
110 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
111 TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
112 TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
113 FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
115 /* Field combinations that are legal for mode 2 form 1 or form 2 reads */
116 static const uint8_t legal_xa_fields[] =
117 { TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
118 TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
119 TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
120 FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
122 /**
123 * Position per sector mode of each of the fields
124 * sync, header, subheader, data, ecc.
125 *
126 */
127 static const uint32_t sector_field_positions[][6] = {
128 { 0, 0, 0, 0, 0, 0 }, /* Unknown */
129 { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
130 { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
131 { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
132 { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
133 { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
137 /**
138 * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
139 * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
140 * will return BADREADMODE, as it's impossible to tell.
141 *
142 * @param track_mode one of the CDROM_MODE* constants
143 * @param read_mode the full read mode
144 */
145 static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
146 {
147 int read_sector_type = CDROM_READ_TYPE(read_mode);
148 int read_sector_fields = CDROM_READ_FIELDS(read_mode);
150 /* Check the sector type is consistent */
151 switch( read_sector_type ) {
152 case CDROM_READ_ANY: break;
153 case CDROM_READ_CDDA:
154 if( sector_mode != SECTOR_CDDA )
155 return CDROM_ERROR_BADREADMODE;
156 break;
157 case CDROM_READ_MODE1:
158 case CDROM_READ_MODE2_FORM1:
159 if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
160 return CDROM_ERROR_BADREADMODE;
161 break;
162 case CDROM_READ_MODE2_FORM2:
163 if( sector_mode != SECTOR_MODE2_FORM2 )
164 return CDROM_ERROR_BADREADMODE;
165 break;
166 case CDROM_READ_MODE2:
167 if( sector_mode != SECTOR_MODE2_FORMLESS )
168 return CDROM_ERROR_BADREADMODE;
169 break;
170 default: /* Illegal read mode */
171 return CDROM_ERROR_BADFIELD;
172 }
174 /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
175 switch( sector_mode ) {
176 case SECTOR_CDDA:
177 return CDROM_ERROR_OK; /* Everything is OK */
178 case SECTOR_MODE2_FORM1:
179 case SECTOR_MODE2_FORM2:
180 if( !legal_xa_fields[read_sector_fields>>11] )
181 return CDROM_ERROR_BADFIELD;
182 else
183 return CDROM_ERROR_OK;
184 case SECTOR_MODE1:
185 case SECTOR_MODE2_FORMLESS:
186 if( !legal_nonxa_fields[read_sector_fields>>11] )
187 return CDROM_ERROR_BADFIELD;
188 else
189 return CDROM_ERROR_OK;
190 default:
191 return CDROM_ERROR_BADFIELD;
192 }
193 }
195 static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
196 {
197 struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
199 switch( raw_mode ) {
200 case SECTOR_SEMIRAW_MODE2: /* XA sectors */
201 case SECTOR_RAW_XA:
202 switch( header->mode ) {
203 case 1: return SECTOR_MODE1;
204 case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
205 default: return SECTOR_UNKNOWN;
206 }
207 case SECTOR_RAW_NONXA:
208 switch( header->mode ) {
209 case 1: return SECTOR_MODE1;
210 case 2: return SECTOR_MODE2_FORMLESS;
211 default: return SECTOR_UNKNOWN;
212 }
213 default:
214 return raw_mode;
215 }
216 }
218 /**
219 * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
220 * necessary.
221 */
222 static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
223 {
224 cdrom_error_t err;
226 switch( device->mode ) {
227 case SECTOR_RAW_XA:
228 case SECTOR_RAW_NONXA:
229 return device->read_blocks(device, lba, 1, buf);
230 case SECTOR_SEMIRAW_MODE2:
231 memcpy( buf, cdrom_sync_data, 12 );
232 cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
233 return device->read_blocks(device, lba, 1, &buf[16]);
234 case SECTOR_MODE1:
235 case SECTOR_MODE2_FORMLESS:
236 err = device->read_blocks(device, lba, 1, &buf[16]);
237 if( err == CDROM_ERROR_OK ) {
238 do_encode_L2( buf, device->mode, lba );
239 }
240 return err;
241 case SECTOR_MODE2_FORM1:
242 *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
243 err = device->read_blocks(device, lba, 1, &buf[24]);
244 if( err == CDROM_ERROR_OK ) {
245 do_encode_L2( buf, device->mode, lba );
246 }
247 return err;
248 case SECTOR_MODE2_FORM2:
249 *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
250 err = device->read_blocks(device, lba, 1, &buf[24]);
251 if( err == CDROM_ERROR_OK ) {
252 do_encode_L2( buf, device->mode, lba );
253 }
254 return err;
255 default:
256 abort();
257 }
258 }
260 static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
261 {
262 int start=-1,end=0;
263 int i;
265 for( i=0; i<5; i++ ) {
266 if( fields & (0x8000>>i) ) {
267 if( start == -1 )
268 start = sector_field_positions[mode][i];
269 else if( end != sector_field_positions[mode][i] )
270 return CDROM_ERROR_BADFIELD;
271 end = sector_field_positions[mode][i+1];
272 }
273 }
274 if( start == -1 ) {
275 *length = 0;
276 } else {
277 memcpy( buf, &raw_sector[start], end-start );
278 *length = end-start;
279 }
280 return CDROM_ERROR_OK;
281 }
283 cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
284 {
285 sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
286 if( sector_mode == SECTOR_UNKNOWN )
287 return CDROM_ERROR_BADREAD;
288 cdrom_error_t status = is_legal_read( sector_mode, mode );
289 if( status != CDROM_ERROR_OK )
290 return status;
291 return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
292 }
294 /**
295 * This is horribly complicated by the need to handle mapping between all possible
296 * sector modes + read modes, but fortunately most sources can just supply
297 * a single block type and not care about the details here.
298 */
299 cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
300 cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
301 unsigned char *buf, size_t *length )
302 {
303 unsigned char tmp[CDROM_MAX_SECTOR_SIZE];
304 int read_sector_type = CDROM_READ_TYPE(mode);
305 int read_sector_fields = CDROM_READ_FIELDS(mode);
306 int i;
307 size_t len = 0;
308 cdrom_error_t err;
310 CHECK_READ(device, lba, count);
312 switch(device->mode) {
313 case SECTOR_CDDA:
314 if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
315 return CDROM_ERROR_BADREADMODE;
316 if( read_sector_fields != 0 ) {
317 len = block_count * CDROM_MAX_SECTOR_SIZE;
318 device->read_blocks( device, lba, block_count, buf );
319 }
320 break;
321 case SECTOR_RAW_XA:
322 case SECTOR_RAW_NONXA:
323 case SECTOR_SEMIRAW_MODE2:
324 /* We (may) have to break the raw sector up into requested fields.
325 * Process sectors one at a time
326 */
327 for( i=0; i<block_count; i++ ) {
328 size_t tmplen;
329 err = read_raw_sector( device, lba+i, tmp );
330 if( err != CDROM_ERROR_OK )
331 return err;
332 err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
333 if( err != CDROM_ERROR_OK )
334 return err;
335 len += tmplen;
336 }
337 break;
338 default: /* Data-only blocks */
339 err = is_legal_read( device->mode, mode );
340 if( err != CDROM_ERROR_OK )
341 return err;
342 if( read_sector_fields == 0 ) { /* Read nothing */
343 *length = 0;
344 return CDROM_ERROR_OK;
345 } else if( read_sector_fields == CDROM_READ_DATA ) {
346 /* Data-only */
347 *length = block_count * CDROM_SECTOR_SIZE(device->mode);
348 return device->read_blocks( device, lba, block_count, buf );
349 } else if( read_sector_fields == CDROM_READ_RAW ) {
350 for( i=0; i<block_count; i++ ) {
351 err = read_raw_sector( device, lba+i, &buf[2352*i] );
352 if( err != CDROM_ERROR_OK )
353 return err;
354 }
355 len = block_count * CDROM_MAX_SECTOR_SIZE;
356 } else {
357 for( i=0; i<block_count; i++ ) {
358 size_t tmplen;
359 err = read_raw_sector( device, lba+i, tmp );
360 if( err != CDROM_ERROR_OK )
361 return err;
362 err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
363 if( err != CDROM_ERROR_OK )
364 return err;
365 len += tmplen;
366 }
367 }
368 }
369 *length = len;
370 return CDROM_ERROR_OK;
372 }
374 /************************ Base implementation *************************/
376 /**
377 * Default destroy implementation - clears the tag and frees memory.
378 */
379 void default_sector_source_destroy( sector_source_t device )
380 {
381 assert( device != NULL && device->ref_count == 0 );
382 device->tag = 0;
383 g_free( device );
384 }
386 sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
387 sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
388 {
389 device->tag = SECTOR_SOURCE_TAG;
390 device->ref_count = 0;
391 device->type = type;
392 device->mode = mode;
393 device->size = size;
394 device->read_blocks = readfn;
395 device->read_sectors = default_sector_source_read_sectors;
396 if( destroyfn == NULL )
397 device->destroy = default_sector_source_destroy;
398 else
399 device->destroy = destroyfn;
400 return device;
401 }
403 /************************ Null device implementation *************************/
404 cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
405 {
406 memset( buf, 0, block_count*CDROM_SECTOR_SIZE(device->mode) );
407 return CDROM_ERROR_OK;
408 }
410 sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
411 {
412 return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
413 null_sector_source_read, default_sector_source_destroy );
414 }
416 /************************ File device implementation *************************/
417 typedef struct file_sector_source {
418 struct sector_source dev;
419 FILE *file;
420 uint32_t offset; /* offset in file where source begins */
421 sector_source_t ref; /* Parent source reference */
422 gboolean closeOnDestroy;
423 } *file_sector_source_t;
425 void file_sector_source_destroy( sector_source_t dev )
426 {
427 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
428 file_sector_source_t fdev = (file_sector_source_t)dev;
430 if( fdev->closeOnDestroy && fdev->file != NULL ) {
431 fclose( fdev->file );
432 }
433 sector_source_unref( fdev->ref );
434 fdev->file = NULL;
435 default_sector_source_destroy(dev);
436 }
438 cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
439 {
440 assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
441 file_sector_source_t fdev = (file_sector_source_t)dev;
443 uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
444 uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
445 fseek( fdev->file, off, SEEK_SET );
447 size_t len = fread( buf, 1, size, fdev->file );
448 if( len == -1 ) {
449 return CDROM_ERROR_READERROR;
450 } else if( len < size ) {
451 /* zero-fill */
452 memset( buf + len, 0, size-len );
453 }
454 return CDROM_ERROR_OK;
455 }
457 sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
458 cdrom_count_t sector_count, gboolean closeOnDestroy )
459 {
460 if( sector_count == FILE_SECTOR_FULL_FILE ) {
461 unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
462 if( sector_size == 0 )
463 sector_size = 2048;
464 struct stat st;
466 if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
467 /* can't stat file? */
468 return NULL;
469 }
471 sector_count = (st.st_size + sector_size-1) / sector_size;
472 }
474 file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
475 dev->file = f;
476 dev->offset = offset;
477 dev->closeOnDestroy = closeOnDestroy;
478 dev->ref = NULL;
479 return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode, sector_count, file_sector_source_read, file_sector_source_destroy );
480 }
482 sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
483 {
484 return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
485 }
487 sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
488 cdrom_count_t sector_count )
489 {
490 int fd = open( filename, O_RDONLY|O_NONBLOCK );
491 if( fd == -1 ) {
492 return NULL;
493 }
494 FILE *f = fdopen( fd , "ro" );
495 if( f == NULL ) {
496 close(fd);
497 return NULL;
498 } else {
499 return file_sector_source_new( f, mode, offset, sector_count, TRUE );
500 }
501 }
503 sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
504 cdrom_count_t sector_count )
505 {
506 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
507 file_sector_source_t fref = (file_sector_source_t)ref;
509 sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
510 ((file_sector_source_t)source)->ref = ref;
511 sector_source_ref(ref);
512 return source;
513 }
515 FILE *file_sector_source_get_file( sector_source_t ref )
516 {
517 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
518 file_sector_source_t fref = (file_sector_source_t)ref;
519 return fref->file;
520 }
522 int file_sector_source_get_fd( sector_source_t ref )
523 {
524 return fileno(file_sector_source_get_file(ref));
525 }
527 void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
528 {
529 assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
530 file_sector_source_t fref = (file_sector_source_t)ref;
531 fref->closeOnDestroy = closeOnDestroy;
532 }
534 /************************ Track device implementation *************************/
535 typedef struct track_sector_source {
536 struct sector_source dev;
537 cdrom_disc_t disc;
538 uint32_t start_lba;
539 } *track_sector_source_t;
541 cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
542 unsigned char *out )
543 {
544 size_t length;
545 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
546 assert( dev->mode != SECTOR_UNKNOWN );
547 track_sector_source_t tdev = (track_sector_source_t)dev;
548 return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
549 }
551 cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
552 cdrom_read_mode_t mode, unsigned char *out, size_t *length )
553 {
554 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
555 track_sector_source_t tdev = (track_sector_source_t)dev;
557 return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
558 }
560 void track_sector_source_destroy( sector_source_t dev )
561 {
562 assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
563 track_sector_source_t tdev = (track_sector_source_t)dev;
564 sector_source_unref( &tdev->disc->source );
565 default_sector_source_destroy(dev);
566 }
568 sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
569 {
570 if( disc == NULL ) {
571 return NULL;
572 }
573 track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
574 dev->disc = disc;
575 dev->start_lba = lba;
576 sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
577 track_sector_source_read_blocks, track_sector_source_destroy );
578 dev->dev.read_sectors = track_sector_source_read_sectors;
579 sector_source_ref( &disc->source );
580 return &dev->dev;
581 }
.