?? mcd.c.txt
字號:
1 /*
2 linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
3
4 Copyright (C) 1992 Martin Harriss
5
6 martin@bdsi.com
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, or (at your option)
11 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
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 HISTORY
23
24 0.1 First attempt - internal use only
25 0.2 Cleaned up delays and use of timer - alpha release
26 0.3 Audio support added
27 0.3.1 Changes for mitsumi CRMC LU005S march version
28 (stud11@cc4.kuleuven.ac.be)
29 0.3.2 bug fixes to the ioclts and merged with ALPHA0.99-pl12
30 (Jon Tombs <jon@robots.ox.ac.uk>)
31 0.3.3 Added more #defines and mcd_setup()
32 (Jon Tombs <jon@gtex02.us.es>)
33 */
34
35
36 #include <linux/errno.h>
37 #include <linux/signal.h>
38 #include <linux/sched.h>
39 #include <linux/timer.h>
40 #include <linux/fs.h>
41 #include <linux/kernel.h>
42 #include <linux/cdrom.h>
43 #include <linux/ioport.h>
44
45 /* #define REALLY_SLOW_IO */
46 #include <asm/system.h>
47 #include <asm/io.h>
48 #include <asm/segment.h>
49
50 #define MAJOR_NR MITSUMI_CDROM_MAJOR
51 #include "blk.h"
52 #include <linux/mcd.h>
53
54 #if 0
55 static int mcd_sizes[] = { 0 };
56 #endif
57
58 static int mcdPresent = 0;
59
60 static char mcd_buf[2048]; /* buffer for block size conversion */
61 static int mcd_bn = -1;
62 static short mcd_port = MCD_BASE_ADDR;
63 static int mcd_irq = MCD_INTR_NR;
64
65 static int McdTimeout, McdTries;
66 static struct wait_queue *mcd_waitq = NULL;
67
68 static struct mcd_DiskInfo DiskInfo;
69 static struct mcd_Toc Toc[MAX_TRACKS];
70 static struct mcd_Play_msf mcd_Play;
71
72 static int audioStatus;
73 static char mcdDiskChanged;
74 static char tocUpToDate;
75 static char mcdVersion;
76
77 static void mcd_transfer(void);
78 static void mcd_start(void);
79 static void mcd_status(void);
80 static void mcd_read_cmd(void);
81 static void mcd_data(void);
82 static void do_mcd_request(void);
83 static void hsg2msf(long hsg, struct msf *msf);
84 static void bin2bcd(unsigned char *p);
85 static int bcd2bin(unsigned char bcd);
86 static int mcdStatus(void);
87 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
88 static int getMcdStatus(int timeout);
89 static int GetQChannelInfo(struct mcd_Toc *qp);
90 static int updateToc(void);
91 static int GetDiskInfo(void);
92 static int GetToc(void);
93 static int getValue(unsigned char *result);
94
95
96 void mcd_setup(char *str, int *ints)
97 {
98 if (ints[0] > 0)
99 mcd_port = ints[1];
100 if (ints[0] > 1)
101 mcd_irq = ints[2];
102 }
103
104
105 int
106 check_mcd_media_change(int full_dev, int flag)
107 {
108 int retval, target;
109
110
111 #if 1 /* the below is not reliable */
112 return 0;
113 #endif
114 target = MINOR(full_dev);
115
116 if (target > 0) {
117 printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
118 return 0;
119 }
120
121 retval = mcdDiskChanged;
122 if (!flag)
123 {
124 mcdDiskChanged = 0;
125 }
126
127 return retval;
128 }
129
130
131 /*
132 * Do a 'get status' command and get the result. Only use from the top half
133 * because it calls 'getMcdStatus' which sleeps.
134 */
135
136 static int
137 statusCmd(void)
138 {
139 int st, retry;
140
141 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
142 {
143
144 outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
145 st = getMcdStatus(MCD_STATUS_DELAY);
146 if (st != -1)
147 break;
148 }
149
150 return st;
151 }
152
153
154 /*
155 * Send a 'Play' command and get the status. Use only from the top half.
156 */
157
158 static int
159 mcdPlay(struct mcd_Play_msf *arg)
160 {
161 int retry, st;
162
163 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
164 {
165 sendMcdCmd(MCMD_PLAY_READ, arg);
166 st = getMcdStatus(2 * MCD_STATUS_DELAY);
167 if (st != -1)
168 break;
169 }
170
171 return st;
172 }
173
174
175 long
176 msf2hsg(struct msf *mp)
177 {
178 return bcd2bin(mp -> frame)
179 + bcd2bin(mp -> sec) * 75
180 + bcd2bin(mp -> min) * 4500
181 - 150;
182 }
183
184
185 static int
186 mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
187 unsigned long arg)
188 {
189 int i, st;
190 struct mcd_Toc qInfo;
191 struct cdrom_ti ti;
192 struct cdrom_tochdr tocHdr;
193 struct cdrom_msf msf;
194 struct cdrom_tocentry entry;
195 struct mcd_Toc *tocPtr;
196 struct cdrom_subchnl subchnl;
197 #if 0
198 struct cdrom_volctrl volctrl;
199 #endif
200
201 if (!ip)
202 return -EINVAL;
203
204 st = statusCmd();
205 if (st < 0)
206 return -EIO;
207
208 if (!tocUpToDate)
209 {
210 i = updateToc();
211 if (i < 0)
212 return i; /* error reading TOC */
213 }
214
215 switch (cmd)
216 {
217 case CDROMSTART: /* Spin up the drive */
218 /* Don't think we can do this. Even if we could,
219 * I think the drive times out and stops after a while
220 * anyway. For now, ignore it.
221 */
222
223 return 0;
224
225 case CDROMSTOP: /* Spin down the drive */
226 outb(MCMD_STOP, MCDPORT(0));
227 i = getMcdStatus(MCD_STATUS_DELAY);
228
229 /* should we do anything if it fails? */
230
231 audioStatus = CDROM_AUDIO_NO_STATUS;
232 return 0;
233
234 case CDROMPAUSE: /* Pause the drive */
235 if (audioStatus != CDROM_AUDIO_PLAY)
236 return -EINVAL;
237
238 outb(MCMD_STOP, MCDPORT(0));
239 i = getMcdStatus(MCD_STATUS_DELAY);
240
241 if (GetQChannelInfo(&qInfo) < 0)
242 {
243 /* didn't get q channel info */
244
245 audioStatus = CDROM_AUDIO_NO_STATUS;
246 return 0;
247 }
248
249 mcd_Play.start = qInfo.diskTime; /* remember restart point */
250
251 audioStatus = CDROM_AUDIO_PAUSED;
252 return 0;
253
254 case CDROMRESUME: /* Play it again, Sam */
255 if (audioStatus != CDROM_AUDIO_PAUSED)
256 return -EINVAL;
257
258 /* restart the drive at the saved position. */
259
260 i = mcdPlay(&mcd_Play);
261 if (i < 0)
262 {
263 audioStatus = CDROM_AUDIO_ERROR;
264 return -EIO;
265 }
266
267 audioStatus = CDROM_AUDIO_PLAY;
268 return 0;
269
270 case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
271
272 st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
273 if (st)
274 return st;
275
276 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
277
278 if (ti.cdti_trk0 < DiskInfo.first
279 || ti.cdti_trk0 > DiskInfo.last
280 || ti.cdti_trk1 < ti.cdti_trk0)
281 {
282 return -EINVAL;
283 }
284
285 if (ti.cdti_trk1 > DiskInfo.last)
286 ti. cdti_trk1 = DiskInfo.last;
287
288 mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
289 mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
290
291 #ifdef MCD_DEBUG
292 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
293 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
294 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
295 #endif
296
297 i = mcdPlay(&mcd_Play);
298 if (i < 0)
299 {
300 audioStatus = CDROM_AUDIO_ERROR;
301 return -EIO;
302 }
303
304 audioStatus = CDROM_AUDIO_PLAY;
305 return 0;
306
307 case CDROMPLAYMSF: /* Play starting at the given MSF address. */
308
309 if (audioStatus == CDROM_AUDIO_PLAY) {
310 outb(MCMD_STOP, MCDPORT(0));
311 i = getMcdStatus(MCD_STATUS_DELAY);
312 audioStatus = CDROM_AUDIO_NO_STATUS;
313 }
314
315 st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
316 if (st)
317 return st;
318
319 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
320
321 /* convert to bcd */
322
323 bin2bcd(&msf.cdmsf_min0);
324 bin2bcd(&msf.cdmsf_sec0);
325 bin2bcd(&msf.cdmsf_frame0);
326 bin2bcd(&msf.cdmsf_min1);
327 bin2bcd(&msf.cdmsf_sec1);
328 bin2bcd(&msf.cdmsf_frame1);
329
330 mcd_Play.start.min = msf.cdmsf_min0;
331 mcd_Play.start.sec = msf.cdmsf_sec0;
332 mcd_Play.start.frame = msf.cdmsf_frame0;
333 mcd_Play.end.min = msf.cdmsf_min1;
334 mcd_Play.end.sec = msf.cdmsf_sec1;
335 mcd_Play.end.frame = msf.cdmsf_frame1;
336
337 #ifdef MCD_DEBUG
338 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
339 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
340 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
341 #endif
342
343 i = mcdPlay(&mcd_Play);
344 if (i < 0)
345 {
346 audioStatus = CDROM_AUDIO_ERROR;
347 return -EIO;
348 }
349
350 audioStatus = CDROM_AUDIO_PLAY;
351 return 0;
352
353 case CDROMREADTOCHDR: /* Read the table of contents header */
354 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
355 if (st)
356 return st;
357
358 tocHdr.cdth_trk0 = DiskInfo.first;
359 tocHdr.cdth_trk1 = DiskInfo.last;
360 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
361 return 0;
362
364
365 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
366 if (st)
367 return st;
368
369 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
370 if (entry.cdte_track == CDROM_LEADOUT)
371 /* XXX */
372 tocPtr = &Toc[DiskInfo.last + 1];
373
374 else if (entry.cdte_track > DiskInfo.last
375 || entry.cdte_track < DiskInfo.first)
376 return -EINVAL;
377
378 else
379 tocPtr = &Toc[entry.cdte_track];
380
381 entry.cdte_adr = tocPtr -> ctrl_addr;
382 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
383
384 if (entry.cdte_format == CDROM_LBA)
385 entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
386
387 else if (entry.cdte_format == CDROM_MSF)
388 {
389 entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
390 entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
391 entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
392 }
393
394 else
395 return -EINVAL;
396
397 memcpy_tofs((void *) arg, &entry, sizeof entry);
398 return 0;
399
400 case CDROMSUBCHNL: /* Get subchannel info */
401
402 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
403 if (st)
404 return st;
405
406 memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
407
408 if (GetQChannelInfo(&qInfo) < 0)
409 return -EIO;
410
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -