Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / icedax / ioctl.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)ioctl.c  1.22 06/02/19 Copyright 1998,1999,2000 Heiko Eissfeldt, Copyright 2006 J. Schilling */
14 /***
15  * CopyPolicy: GNU Public License 2 applies
16  * Copyright (C) 1999 Heiko Eissfeldt heiko@colossus.escape.de
17  *
18  * Ioctl interface module for cdrom drive access
19  *
20  * Solaris ATAPI cdrom drives are untested!
21  *
22  */
23 #include "config.h"
24 #include <stdio.h>
25 #include <standard.h>
26 #include <stdxlib.h>
27 #include <unixstd.h>
28 #include <strdefs.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <fctldefs.h>
32 #include <assert.h>
33
34 #include <sys/ioctl.h>
35 #include <statdefs.h>
36 #include <schily.h>
37 #include <device.h>
38
39 #include <usal/scsitransp.h>
40
41 #include "mycdrom.h"
42 #include "lowlevel.h"
43 /* some include file locations have changed with newer kernels */
44 #if defined (__linux__)
45 # if LINUX_VERSION_CODE > 0x10300 + 97
46 #  if LINUX_VERSION_CODE < 0x200ff
47 #   include <linux/sbpcd.h>
48 #   include <linux/ucdrom.h>
49 #  endif
50 #  if !defined(CDROM_SELECT_SPEED)
51 #   include <linux/ucdrom.h>
52 #  endif
53 # endif
54 #endif
55
56 #include "mytype.h"
57 #include "byteorder.h"
58 #include "interface.h"
59 #include "toc.h"
60 #include "icedax.h"
61 #include "ioctl.h"
62 #include "global.h"
63 #include "exitcodes.h"
64
65 #include <utypes.h>
66 #include <wodim.h>
67
68 #if defined (HAVE_IOCTL_INTERFACE)
69 #if  !defined(sun) && !defined(__sun) && !(defined(__FreeBSD__) && (__FreeBSD_version >= 501112))
70 static struct cdrom_read_audio arg;
71 #endif
72
73 #if (defined(__FreeBSD__) && __FreeBSD_version >= 400014) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
74 static unsigned sector_size;
75 #endif
76
77 static int err;
78
79 static void EnableCdda_cooked(SCSI *usalp, int fAudioMode, unsigned uSectorsize);
80 /* ARGSUSED */
81 static void EnableCdda_cooked(SCSI *usalp, int fAudioMode, unsigned uSectorsize)
82 {
83 #if     (defined(__FreeBSD__) && __FreeBSD_version >= 400014) || defined(__DragonFly__)  || defined(__FreeBSD_kernel__)
84         if (usalp && usalp->verbose)
85                 fprintf(stderr, "EnableCdda_cooked (CDRIOCSETBLOCKSIZE)...\n");
86
87         if (fAudioMode) {
88                 if (ioctl(global.cooked_fd, CDRIOCGETBLOCKSIZE, &sector_size) ==-1)
89                         sector_size = CD_FRAMESIZE;
90                 ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, &uSectorsize);
91         } else
92                 ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, &sector_size);
93 #else
94 #if     defined CDIOCSETCDDA
95         if (usalp && usalp->verbose) {
96                 fprintf(stderr, "EnableCdda_cooked (CDIOCSETCDDA)...\n");
97                 if (uSectorsize != CD_FRAMESIZE_RAW)
98                         fprintf(stderr, "non audio sector size is ignored.\n");
99         }
100
101         ioctl(global.cooked_fd, CDIOCSETCDDA, &fAudioMode);
102 #else
103         fprintf(stderr, "EnableCdda_cooked (CDIOCSETCDDA) is not available...\n");
104 #endif
105 #endif
106
107 }
108
109
110 static unsigned ReadToc_cooked(SCSI *x);
111
112 /* read the table of contents (toc) via the ioctl interface */
113 static unsigned ReadToc_cooked(SCSI *x)
114 {
115     unsigned i;
116     unsigned tracks;
117     struct cdrom_tochdr hdr;
118     struct cdrom_tocentry entry[100];
119     struct cdrom_tocentry entryMSF[100];
120
121     if (x && x->verbose) {
122         fprintf(stderr, "ReadToc_cooked (CDROMREADTOCHDR)...\n");
123     }
124
125     /* get TocHeader to find out how many entries there are */
126     err = ioctl( global.cooked_fd, CDROMREADTOCHDR, &hdr );
127     if ( err != 0 ) {
128         /* error handling */
129         if (err == -1) {
130             if (errno == EPERM)
131                 fprintf( stderr, "Please run this program setuid root.\n");
132             perror("cooked: Read TOC ");
133             exit( DEVICE_ERROR );
134         } else {
135             fprintf( stderr, "can't get TocHeader (error %d).\n", err );
136             exit( MEDIA_ERROR );
137         }
138     }
139     /* get all TocEntries */
140     for ( i = 0; i < hdr.cdth_trk1; i++ ) {
141         entryMSF[i].cdte_track = 1+i;
142         entryMSF[i].cdte_format = CDROM_MSF;
143         err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i] );
144         if ( err != 0 ) {
145             /* error handling */
146             fprintf( stderr, "can't get TocEntry #%d msf (error %d).\n", i+1, err );
147             exit( MEDIA_ERROR );
148         }
149     }
150     entryMSF[i].cdte_track = CDROM_LEADOUT;
151     entryMSF[i].cdte_format = CDROM_MSF;
152     err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i] );
153     if ( err != 0 ) {
154         /* error handling */
155         fprintf( stderr, "can't get TocEntry LEADOUT msf (error %d).\n", err );
156         exit( MEDIA_ERROR );
157     }
158     tracks = hdr.cdth_trk1+1;
159 /*
160     for (i = 0; i < tracks; i++) {
161         toc[i].bFlags = (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f);
162         toc[i].bTrack = entry[i].cdte_track;
163         toc[i].mins = entry[i].cdte_addr.msf.minute;
164         toc[i].secs = entry[i].cdte_addr.msf.second;
165         toc[i].frms = entry[i].cdte_addr.msf.frame;
166     }
167 */
168     /* get all TocEntries now in lba format */
169     for ( i = 0; i < hdr.cdth_trk1; i++ ) {
170         entry[i].cdte_track = 1+i;
171         entry[i].cdte_format = CDROM_LBA;
172         err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] );
173         if ( err != 0 ) {
174             /* error handling */
175             fprintf( stderr, "can't get TocEntry #%d lba (error %d).\n", i+1, err );
176             exit( MEDIA_ERROR );
177         }
178 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
179         entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba);
180 #endif
181     }
182     entry[i].cdte_track = CDROM_LEADOUT;
183     entry[i].cdte_format = CDROM_LBA;
184     err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] );
185     if ( err != 0 ) {
186         /* error handling */
187         fprintf( stderr, "can't get TocEntry LEADOUT lba (error %d).\n", err );
188         exit( MEDIA_ERROR );
189     }
190 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
191     entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba);
192 #endif
193
194     for (i = 0; i < tracks; i++) {
195         toc_entry(i+1,
196                   (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f),
197                   entry[i].cdte_track,
198                   NULL /* ISRC */,
199                   entry[i].cdte_addr.lba,
200                   entryMSF[i].cdte_addr.msf.minute,
201                   entryMSF[i].cdte_addr.msf.second,
202                   entryMSF[i].cdte_addr.msf.frame);
203     }
204     bufferTOC[0] = '\0';
205     bufferTOC[1] = '\0';
206     return --tracks;           /* without lead-out */
207 }
208
209 static void trash_cache_cooked(UINT4 *p, unsigned lSector, 
210                                                                                  unsigned SectorBurstVal);
211
212 static void trash_cache_cooked(UINT4 *p, unsigned lSector, 
213                                unsigned SectorBurstVal)
214 {
215       /* trash the cache */
216
217 #if     defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
218 #if     defined(__FreeBSD__) && __FreeBSD_version >= 501112
219       pread(global.cooked_fd, (void *) &p[0], 3*CD_FRAMESIZE_RAW,
220           find_an_off_sector(lSector, SectorBurstVal)*CD_FRAMESIZE_RAW);
221 #else
222       static struct cdrom_read_audio arg2;
223
224       arg2.address.lba = find_an_off_sector(lSector, SectorBurstVal);
225       arg2.addr_format = CDROM_LBA;
226       arg2.nframes = 3;
227       arg2.buffer = (unsigned char *) &p[0];
228
229       ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);
230 #endif
231 #endif
232 #if     defined __linux__
233       static struct cdrom_read_audio arg2;
234
235       arg2.addr.lba = find_an_off_sector(lSector, SectorBurstVal);
236       arg2.addr_format = CDROM_LBA;
237       arg2.nframes = 3;
238       arg2.buf = (unsigned char *) &p[0];
239
240       ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);
241 #endif
242 #if     defined __sun || (defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE)
243       struct cdrom_cdda suncdda;
244
245       suncdda.cdda_addr = lSector;
246       suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW;
247       suncdda.cdda_data = (char *) &p[0];
248       suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
249  
250       ioctl(global.cooked_fd, CDROMCDDA, &suncdda);
251 #endif
252 }
253
254 static void ReadCdRomData_cooked(SCSI *x, UINT4 *p, unsigned lSector, 
255                                                                                         unsigned SectorBurstVal);
256 /* read 'SectorBurst' adjacent sectors of data sectors 
257  * to Buffer '*p' beginning at sector 'lSector'
258  */
259 static void ReadCdRomData_cooked(SCSI *x, UINT4 *p, unsigned lSector, 
260                                  unsigned SectorBurstVal)
261 {
262         int     retval;
263
264         if (x && x->verbose) {
265                 fprintf(stderr, "ReadCdRomData_cooked (lseek & read)...\n");
266         }
267
268         if ((retval = lseek(global.cooked_fd, lSector*CD_FRAMESIZE, SEEK_SET))
269                 != (int)lSector*CD_FRAMESIZE) { perror("cannot seek sector"); }
270         if ((retval = read(global.cooked_fd, p, SectorBurstVal*CD_FRAMESIZE))
271                 != (int)SectorBurstVal*CD_FRAMESIZE) { perror("cannot read sector"); }
272
273         return;
274 }
275
276 static int ReadCdRom_cooked(SCSI *x, UINT4 *p, unsigned lSector, 
277                                                                          unsigned SectorBurstVal);
278 /* read 'SectorBurst' adjacent sectors of audio sectors 
279  * to Buffer '*p' beginning at sector 'lSector'
280  */
281 static int ReadCdRom_cooked(SCSI *x, UINT4 *p, unsigned lSector, 
282                             unsigned SectorBurstVal)
283 {
284   int retry_count=0;
285   static int nothing_read = 1;
286
287 /* read 2352 bytes audio data */
288 #if     defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
289 #if     defined(__FreeBSD__) && __FreeBSD_version >= 501112
290     if (x && x->verbose) {
291         fprintf(stderr, "ReadCdRom_cooked (pread)...\n");
292     }
293
294   do {
295     err = 0;
296     if (pread(global.cooked_fd, (void *) &p[0], SectorBurstVal*CD_FRAMESIZE_RAW,
297         lSector*CD_FRAMESIZE_RAW) == -1)
298                 err = -1;
299 #else
300   arg.address.lba = lSector;
301   arg.addr_format = CDROM_LBA;
302   arg.nframes = SectorBurstVal;
303   arg.buffer = (unsigned char *) &p[0];
304
305     if (x && x->verbose) {
306         fprintf(stderr, "ReadCdRom_cooked (CDROMREADAUDIO)...\n");
307     }
308
309   do {
310     err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);
311 #endif
312 #endif
313 #if     defined __linux__
314   arg.addr.lba = lSector;
315   arg.addr_format = CDROM_LBA;
316   arg.nframes = SectorBurstVal;
317   arg.buf = (unsigned char *) &p[0];
318
319     if (x && x->verbose) {
320         fprintf(stderr, "ReadCdRom_cooked (CDROMREADAUDIO)...\n");
321     }
322
323   do {
324     err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);
325 #endif
326 #if     defined __sun || (defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE)
327   struct cdrom_cdda suncdda;
328
329   suncdda.cdda_addr = lSector;
330   suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW;
331   suncdda.cdda_data = (char *) &p[0];
332   suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
333  
334     if (x && x->verbose) {
335         fprintf(stderr, "ReadCdRom_cooked (CDROMCDDA)...\n");
336     }
337
338   do {
339     err = ioctl(global.cooked_fd, CDROMCDDA, &suncdda);
340 #endif
341     retry_count++;
342
343     if (err) { 
344       trash_cache_cooked(p, lSector, SectorBurstVal);
345     }
346
347   } while ((err) && (retry_count < 30));
348   if (err != 0) {
349         if (x->silent == 0) {
350                 /* error handling */
351                 if (err == -1) {
352                         if (nothing_read && (errno == EINVAL || errno == EIO))
353                                 fprintf( stderr, "Sorry, this driver and/or drive does not support cdda reading.\n");
354                         perror("cooked: Read cdda ");
355                         fprintf(stderr, " sector %u + %u, buffer %p + %x\n", lSector, SectorBurstVal, p, global.shmsize);
356                 } else {
357                         fprintf(stderr, "can't read frame #%u (error %d).\n", 
358                                 lSector, err);
359                 }
360         }
361         return SectorBurstVal - 1;
362   } else {
363     nothing_read = 0;
364   }
365
366   return SectorBurstVal;
367 }
368
369 static int StopPlay_cooked(SCSI *x);
370 static int StopPlay_cooked(SCSI *x)
371 {
372     if (x && x->verbose) {
373         fprintf(stderr, "StopPlay_cooked (CDROMSTOP)...\n");
374     }
375
376         return ioctl( global.cooked_fd, CDROMSTOP, 0 ) ? 0 : -1; 
377 }
378
379 static int Play_at_cooked(SCSI *x, unsigned int from_sector, 
380                                                                   unsigned int sectors);
381 static int Play_at_cooked(SCSI *x, unsigned int from_sector, 
382                           unsigned int sectors)
383 {
384         struct cdrom_msf cmsf;
385         int retval;
386
387     if (x && x->verbose) {
388         fprintf(stderr, "Play_at_cooked (CDROMSTART & CDROMPLAYMSF)... (%u-%u)",
389                 from_sector, from_sector+sectors-1);
390         
391         fprintf(stderr, "\n");
392     }
393
394         cmsf.cdmsf_min0 = (from_sector + 150) / (60*75);
395         cmsf.cdmsf_sec0 = ((from_sector + 150) / 75) % 60;
396         cmsf.cdmsf_frame0 = (from_sector + 150) % 75;
397         cmsf.cdmsf_min1 = (from_sector + 150 + sectors) / (60*75);
398         cmsf.cdmsf_sec1 = ((from_sector + 150 + sectors) / 75) % 60;
399         cmsf.cdmsf_frame1 = (from_sector + 150 + sectors) % 75;
400
401 #if     0
402 /* makes index scanning under FreeBSD too slow */
403         if (( retval = ioctl( global.cooked_fd, CDROMSTART, 0 )) != 0){
404                 perror("");
405         }
406 #endif
407         if (( retval = ioctl( global.cooked_fd, CDROMPLAYMSF, &cmsf )) != 0){
408                 perror("");
409         }
410         return retval;
411 }
412
413 /* request sub-q-channel information. This function may cause confusion
414  * for a drive, when called in the sampling process.
415  */
416 static subq_chnl *ReadSubQ_cooked(SCSI *x, unsigned char sq_format, 
417                                                                                          unsigned char track)
418 {
419     struct cdrom_subchnl sub_ch;
420
421 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
422     struct cd_sub_channel_info sub_ch_info;
423
424     if (x && x->verbose) {
425         fprintf(stderr, "ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n");
426     }
427
428     sub_ch.address_format = CD_MSF_FORMAT;
429     sub_ch.track = track;
430     sub_ch.data_len = sizeof(struct cd_sub_channel_info);
431     sub_ch.data = &sub_ch_info;
432
433     switch (sq_format) {
434       case GET_CATALOGNUMBER:
435       sub_ch.data_format = CD_MEDIA_CATALOG;
436 #else
437     if (x && x->verbose) {
438         fprintf(stderr, "ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n");
439     }
440
441     switch (sq_format) {
442       case GET_CATALOGNUMBER:
443 #endif
444 #if     defined CDROM_GET_MCN
445       if (!(err = ioctl(global.cooked_fd, CDROM_GET_MCN, (struct cdrom_mcn *) SubQbuffer))) {
446           subq_chnl *SQp = (subq_chnl *) SubQbuffer;
447           subq_catalog *SQPp = (subq_catalog *) &SQp->data;
448
449           memmove(SQPp->media_catalog_number, SQp, sizeof (SQPp->media_catalog_number));
450           SQPp->zero = 0;
451           SQPp->mc_valid = 0x80;
452           break;
453       } else
454 #endif
455       {
456           return NULL;
457       }
458       case GET_POSITIONDATA:
459 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
460       sub_ch.data_format = CD_CURRENT_POSITION;
461 #endif
462 #if defined (__linux__)
463       sub_ch.cdsc_format = CDROM_MSF;
464 #endif
465       if (!(err = ioctl(global.cooked_fd, CDROMSUBCHNL, &sub_ch))) {
466           /* copy to SubQbuffer */
467           subq_chnl *SQp = (subq_chnl *) (SubQbuffer);
468           subq_position *SQPp = (subq_position *) SQp->data;
469           SQp->audio_status     = sub_ch.cdsc_audiostatus;
470           SQp->format           = sub_ch.cdsc_format;
471           SQp->control_adr      = (sub_ch.cdsc_adr << 4) | (sub_ch.cdsc_ctrl & 0x0f);
472           SQp->track            = sub_ch.cdsc_trk;
473           SQp->index            = sub_ch.cdsc_ind;
474           SQPp->abs_min         = sub_ch.cdsc_absaddr.msf.minute;
475           SQPp->abs_sec         = sub_ch.cdsc_absaddr.msf.second;
476           SQPp->abs_frame       = sub_ch.cdsc_absaddr.msf.frame;
477           SQPp->trel_min        = sub_ch.cdsc_reladdr.msf.minute;
478           SQPp->trel_sec        = sub_ch.cdsc_reladdr.msf.second;
479           SQPp->trel_frame      = sub_ch.cdsc_reladdr.msf.frame;
480       } else {
481           if (err == -1) {
482               if (errno == EPERM)
483                   fprintf( stderr, "Please run this program setuid root.\n");
484               perror("cooked: Read subq ");
485               exit( DEVICE_ERROR );
486           } else {
487               fprintf(stderr, "can't read sub q channel (error %d).\n", err);
488               exit( DEVICE_ERROR );
489           }
490       }
491       break;
492       default:
493           return NULL;
494     } /* switch */
495   return (subq_chnl *)(SubQbuffer);
496 }
497
498 /* Speed control */
499 static void SpeedSelect_cooked(SCSI *x, unsigned speed);
500 /* ARGSUSED */
501 static void SpeedSelect_cooked(SCSI *x, unsigned speed)
502 {
503         if (x && x->verbose) {
504                 fprintf(stderr, "SpeedSelect_cooked (CDROM_SELECT_SPEED)...\n");
505         }
506
507 #ifdef CDROM_SELECT_SPEED
508         /* CAUTION!!!!! Non standard ioctl parameter types here!!!! */
509         if ((err = ioctl(global.cooked_fd, CDROM_SELECT_SPEED, speed))) {
510                 if (err == -1) {
511                         if (errno == EPERM)
512                                 fprintf( stderr, "Please run this program setuid root.\n");
513                         perror("cooked: Speed select ");
514                         /*exit( err ); */
515                 } else {
516                         fprintf(stderr, "can't set speed %d (error %d).\n", speed, err);
517                         exit( DEVICE_ERROR );
518                 }
519         }
520 #endif
521 }
522
523 /* set function pointers to use the ioctl routines */
524 void SetupCookedIoctl(char *pdev_name)
525 {
526 #if (HAVE_ST_RDEV == 1)
527     struct stat statstruct;
528
529     if (fstat(global.cooked_fd, &statstruct)) {
530       fprintf(stderr, "cannot stat cd %d (%s)\n",global.cooked_fd, pdev_name);
531       exit(STAT_ERROR);
532     }
533 #if     defined __linux__
534     switch (major(statstruct.st_rdev)) {
535     case CDU31A_CDROM_MAJOR:    /* sony cdu-31a/33a */
536         global.nsectors = 13;
537         if (global.nsectors >= 14) {
538           global.overlap = 10;
539         }
540         break;
541     case MATSUSHITA_CDROM_MAJOR:        /* sbpcd 1 */
542     case MATSUSHITA_CDROM2_MAJOR:       /* sbpcd 2 */
543     case MATSUSHITA_CDROM3_MAJOR:       /* sbpcd 3 */
544     case MATSUSHITA_CDROM4_MAJOR:       /* sbpcd 4 */
545         /* some are more compatible than others */
546         global.nsectors = 13;
547         break;
548     default:
549         global.nsectors = 8;
550         break;
551     }
552     err = ioctl(global.cooked_fd, CDROMAUDIOBUFSIZ, global.nsectors);
553
554     switch (major(statstruct.st_rdev)) {
555     case MATSUSHITA_CDROM_MAJOR:        /* sbpcd 1 */
556     case MATSUSHITA_CDROM2_MAJOR:       /* sbpcd 2 */
557     case MATSUSHITA_CDROM3_MAJOR:       /* sbpcd 3 */
558     case MATSUSHITA_CDROM4_MAJOR:       /* sbpcd 4 */
559       if (err == -1) {
560         perror("ioctl(CDROMAUDIOBUFSIZ)");
561       }
562     }
563 #endif
564 #endif
565     EnableCdda = EnableCdda_cooked;
566     ReadCdRom = ReadCdRom_cooked;
567     ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned)) ReadCdRomData_cooked;
568     doReadToc = ReadToc_cooked;
569     ReadTocText = NULL;
570     ReadSubQ = ReadSubQ_cooked;
571     ReadSubChannels = NULL;
572     SelectSpeed = SpeedSelect_cooked;
573     Play_at = Play_at_cooked;
574     StopPlay = StopPlay_cooked;
575     trash_cache = trash_cache_cooked;
576     ReadLastAudio = NULL;
577 }
578 #endif