1 /*
2 * cdaccess.c
3 * System-dependent code to access extended CD information
4 *
5 * Based on a contribution by Erik Andersen
6 *
7 * Copyright (c) 2003 Christoph Pfisterer
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use, copy,
13 * modify, merge, publish, distribute, sublicense, and/or sell copies
14 * of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30 #include "global.h"
31
32
33 #ifdef USE_IOCTL_LINUX
34 #include <sys/ioctl.h>
35 #include <linux/cdrom.h>
36 #define DO_CDACCESS 1
37 #endif /* USE_IOCTL_LINUX */
38
39
40 #ifdef DO_CDACCESS
41
42 /*
43 * CDDB stuff
44 */
45
46 static int cddb_sum(int n);
47
48 #define LBA_TO_SECS(lba) (((lba) + 150) / 75)
49
50
51 /*
52 * CD structure:
53 * Tries to get the CD TOC using out-of-band means (i.e. ioctl()),
54 * prints the info, and analyzes just the data tracks. Quite
55 * system-dependent, but layed out for porability.
56 */
57
analyze_cdaccess(int fd,SOURCE * s,int level)58 int analyze_cdaccess(int fd, SOURCE *s, int level)
59 {
60 int i;
61 int first, last, ntracks;
62 int cksum, totaltime, seconds;
63 u4 diskid;
64 u1 ctrl[100];
65 u4 lba[100], length;
66 char human_readable_size[256];
67 #ifdef USE_IOCTL_LINUX
68 struct cdrom_tochdr tochdr;
69 struct cdrom_tocentry tocentry;
70 #endif
71
72 /* read TOC header */
73 #ifdef USE_IOCTL_LINUX
74 if (ioctl(fd, CDROMREADTOCHDR, &tochdr) < 0) {
75 return 0;
76 }
77 first = tochdr.cdth_trk0;
78 last = tochdr.cdth_trk1;
79 #endif
80
81 ntracks = last + 1 - first;
82 if (ntracks > 99) /* natural limit */
83 return 0;
84
85 /* read per-track data from TOC */
86 for (i = 0; i <= ntracks; i++) {
87 #ifdef USE_IOCTL_LINUX
88 if (i == ntracks)
89 tocentry.cdte_track = CDROM_LEADOUT;
90 else
91 tocentry.cdte_track = first + i;
92 tocentry.cdte_format = CDROM_LBA;
93 if (ioctl(fd, CDROMREADTOCENTRY, &tocentry) < 0) {
94 //printf("CDROMREADTOCENTRY: %s: ", strerror(errno));
95 return 0;
96 }
97 ctrl[i] = tocentry.cdte_ctrl;
98 lba[i] = tocentry.cdte_addr.lba;
99 #endif
100 }
101
102 /* System-dependent code ends here. From now on, we use the data
103 in first, last, ntracks, ctrl[], and lba[]. We also assume
104 all systems treat actual data access the same way... */
105
106 /* calculate CDDB disk id */
107 cksum = 0;
108 for (i = 0; i < ntracks; i++) {
109 cksum += cddb_sum(LBA_TO_SECS(lba[i]));
110 }
111 totaltime = LBA_TO_SECS(lba[ntracks]) - LBA_TO_SECS(lba[0]);
112 diskid = (u4)(cksum % 0xff) << 24 | (u4)totaltime << 8 | (u4)ntracks;
113
114 /* print disk info */
115 print_line(level, "CD-ROM, %d track%s, CDDB disk ID %08lX",
116 ntracks, (ntracks != 1) ? "s" : "", diskid);
117
118 /* Loop over each track */
119 for (i = 0; i < ntracks; i++) {
120 /* length of track in sectors */
121 length = lba[i+1] - lba[i];
122
123 if ((ctrl[i] & 0x4) == 0) {
124 /* Audio track, one sector holds 2352 actual data bytes */
125 seconds = length / 75;
126 format_size(human_readable_size, (u8)length * 2352);
127 print_line(level, "Track %d: Audio track, %s, %3d min %02d sec",
128 first + i, human_readable_size,
129 seconds / 60, seconds % 60);
130
131 } else {
132 /* Data track, one sector holds 2048 actual data bytes */
133 format_size(human_readable_size, length * 2048);
134 print_line(level, "Track %d: Data track, %s",
135 first + i, human_readable_size);
136
137 /* NOTE: we adjust the length to stay clear of padding or
138 post-gap stuff */
139 analyze_source_special(s, level + 1,
140 (u8)lba[i] * 2048, (u8)(length - 250) * 2048);
141 }
142 }
143
144 return 1;
145 }
146
147 /*
148 * helper function: calculate cddb disk id
149 */
150
cddb_sum(int n)151 static int cddb_sum(int n)
152 {
153 /* a number like 2344 becomes 2+3+4+4 (13) */
154 int ret = 0;
155
156 while (n > 0) {
157 ret = ret + (n % 10);
158 n = n / 10;
159 }
160
161 return ret;
162 }
163
164
165 #else /* DO_CDACCESS */
166
167 /*
168 * the system is not supported, so use a dummy function
169 */
170
analyze_cdaccess(int fd,SOURCE * s,int level)171 int analyze_cdaccess(int fd, SOURCE *s, int level)
172 {
173 return 0;
174 }
175
176 #endif /* DO_CDACCESS */
177
178
179 /* EOF */
180