FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/wcd.c
1 /*
2 * IDE CD-ROM driver for FreeBSD.
3 * Supports ATAPI-compatible drives.
4 *
5 * Copyright (C) 1995 Cronyx Ltd.
6 * Author Serge Vakulenko, <vak@cronyx.ru>
7 *
8 * This software is distributed with NO WARRANTIES, not even the implied
9 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 *
11 * Authors grant any other persons or organisations permission to use
12 * or modify this software as long as this message is kept with the software,
13 * all derivative works or modified versions.
14 *
15 * Version 1.9, Mon Oct 9 20:27:42 MSK 1995
16 */
17
18 #include "wdc.h"
19 #include "wcd.h"
20 #include "opt_atapi.h"
21
22 #if NWCD > 0 && NWDC > 0 && defined (ATAPI)
23
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/kernel.h>
27 #include <sys/proc.h>
28 #include <sys/malloc.h>
29 #include <sys/buf.h>
30 #include <sys/ioctl.h>
31 #include <sys/disklabel.h>
32 #include <sys/cdio.h>
33 #include <sys/conf.h>
34 #ifdef DEVFS
35 #include <sys/devfsext.h>
36 #endif /*DEVFS*/
37
38 #include <machine/cpufunc.h>
39
40 #include <i386/isa/atapi.h>
41
42 static d_open_t wcdropen;
43 static d_open_t wcdbopen;
44 static d_close_t wcdrclose;
45 static d_close_t wcdbclose;
46 static d_ioctl_t wcdioctl;
47 static d_strategy_t wcdstrategy;
48
49 #define CDEV_MAJOR 69
50 #define BDEV_MAJOR 19
51 extern struct cdevsw wcd_cdevsw;
52 static struct bdevsw wcd_bdevsw =
53 { wcdbopen, wcdbclose, wcdstrategy, wcdioctl, /*19*/
54 nodump, nopsize, 0, "wcd", &wcd_cdevsw, -1 };
55
56 static struct cdevsw wcd_cdevsw =
57 { wcdropen, wcdrclose, rawread, nowrite, /*69*/
58 wcdioctl, nostop, nullreset, nodevtotty,/* atapi */
59 seltrue, nommap, wcdstrategy, "wcd",
60 &wcd_bdevsw, -1 };
61
62 #ifndef ATAPI_STATIC
63 static
64 #endif
65 int wcdattach(struct atapi*, int, struct atapi_params*, int);
66
67 #define NUNIT (NWDC*2) /* Max. number of devices */
68 #define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
69 #define SECSIZE 2048 /* CD-ROM sector size in bytes */
70
71 #define F_BOPEN 0x0001 /* The block device is opened */
72 #define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
73 #define F_DEBUG 0x0004 /* Print debug info */
74
75 /*
76 * Disc table of contents.
77 */
78 #define MAXTRK 99
79 struct toc {
80 struct ioc_toc_header hdr;
81 struct cd_toc_entry tab[MAXTRK+1]; /* One extra for the leadout */
82 };
83
84 /*
85 * Volume size info.
86 */
87 struct volinfo {
88 u_long volsize; /* Volume size in blocks */
89 u_long blksize; /* Block size in bytes */
90 } info;
91
92 /*
93 * Current subchannel status.
94 */
95 struct subchan {
96 u_char void0;
97 u_char audio_status;
98 u_short data_length;
99 u_char data_format;
100 u_char control;
101 u_char track;
102 u_char indx;
103 u_long abslba;
104 u_long rellba;
105 };
106
107 /*
108 * Audio Control Parameters Page
109 */
110 struct audiopage {
111 /* Mode data header */
112 u_short data_length;
113 u_char medium_type;
114 u_char reserved1[5];
115
116 /* Audio control page */
117 u_char page_code;
118 #define AUDIO_PAGE 0x0e
119 #define AUDIO_PAGE_MASK 0x4e /* changeable values */
120 u_char param_len;
121 u_char flags;
122 #define CD_PA_SOTC 0x02 /* mandatory */
123 #define CD_PA_IMMED 0x04 /* always 1 */
124 u_char reserved3[3];
125 u_short lb_per_sec;
126 struct port_control {
127 u_char channels : 4;
128 #define CHANNEL_0 1 /* mandatory */
129 #define CHANNEL_1 2 /* mandatory */
130 #define CHANNEL_2 4 /* optional */
131 #define CHANNEL_3 8 /* optional */
132 u_char volume;
133 } port[4];
134 };
135
136 /*
137 * CD-ROM Capabilities and Mechanical Status Page
138 */
139 struct cappage {
140 /* Mode data header */
141 u_short data_length;
142 u_char medium_type;
143 #define MDT_UNKNOWN 0x00
144 #define MDT_DATA_120 0x01
145 #define MDT_AUDIO_120 0x02
146 #define MDT_COMB_120 0x03
147 #define MDT_PHOTO_120 0x04
148 #define MDT_DATA_80 0x05
149 #define MDT_AUDIO_80 0x06
150 #define MDT_COMB_80 0x07
151 #define MDT_PHOTO_80 0x08
152 #define MDT_NO_DISC 0x70
153 #define MDT_DOOR_OPEN 0x71
154 #define MDT_FMT_ERROR 0x72
155 u_char reserved1[5];
156
157 /* Capabilities page */
158 u_char page_code;
159 #define CAP_PAGE 0x2a
160 u_char param_len;
161 u_char reserved2[2];
162
163 u_char audio_play : 1; /* audio play supported */
164 u_char composite : 1; /* composite audio/video supported */
165 u_char dport1 : 1; /* digital audio on port 1 */
166 u_char dport2 : 1; /* digital audio on port 2 */
167 u_char mode2_form1 : 1; /* mode 2 form 1 (XA) read */
168 u_char mode2_form2 : 1; /* mode 2 form 2 format */
169 u_char multisession : 1; /* multi-session photo-CD */
170 u_char : 1;
171 u_char cd_da : 1; /* audio-CD read supported */
172 u_char cd_da_stream : 1; /* CD-DA streaming */
173 u_char rw : 1; /* combined R-W subchannels */
174 u_char rw_corr : 1; /* R-W subchannel data corrected */
175 u_char c2 : 1; /* C2 error pointers supported */
176 u_char isrc : 1; /* can return the ISRC info */
177 u_char upc : 1; /* can return the catalog number UPC */
178 u_char : 1;
179 u_char lock : 1; /* could be locked */
180 u_char locked : 1; /* current lock state */
181 u_char prevent : 1; /* prevent jumper installed */
182 u_char eject : 1; /* can eject */
183 u_char : 1;
184 u_char mech : 3; /* loading mechanism type */
185 #define MECH_CADDY 0
186 #define MECH_TRAY 1
187 #define MECH_POPUP 2
188 #define MECH_CHANGER 4
189 #define MECH_CARTRIDGE 5
190 u_char sep_vol : 1; /* independent volume of channels */
191 u_char sep_mute : 1; /* independent mute of channels */
192 u_char : 6;
193
194 u_short max_speed; /* max raw data rate in bytes/1000 */
195 u_short max_vol_levels; /* number of discrete volume levels */
196 u_short buf_size; /* internal buffer size in bytes/1024 */
197 u_short cur_speed; /* current data rate in bytes/1000 */
198
199 /* Digital drive output format description (optional?) */
200 u_char reserved3;
201 u_char bckf : 1; /* data valid on failing edge of BCK */
202 u_char rch : 1; /* high LRCK indicates left channel */
203 u_char lsbf : 1; /* set if LSB first */
204 u_char dlen: 2;
205 #define DLEN_32 0 /* 32 BCKs */
206 #define DLEN_16 1 /* 16 BCKs */
207 #define DLEN_24 2 /* 24 BCKs */
208 #define DLEN_24_I2S 3 /* 24 BCKs (I2S) */
209 u_char : 3;
210 u_char reserved4[2];
211 };
212
213 struct wcd {
214 struct atapi *ata; /* Controller structure */
215 int unit; /* IDE bus drive unit */
216 int lun; /* Logical device unit */
217 int flags; /* Device state flags */
218 int refcnt; /* The number of raw opens */
219 struct buf_queue_head buf_queue; /* Queue of i/o requests */
220 struct atapi_params *param; /* Drive parameters table */
221 struct toc toc; /* Table of disc contents */
222 struct volinfo info; /* Volume size info */
223 struct audiopage au; /* Audio page info */
224 struct cappage cap; /* Capabilities page info */
225 struct audiopage aumask; /* Audio page mask */
226 struct subchan subchan; /* Subchannel info */
227 char description[80]; /* Device description */
228 int starting_lba ;
229 #ifdef DEVFS
230 void *ra_devfs_token;
231 void *rc_devfs_token;
232 void *a_devfs_token;
233 void *c_devfs_token;
234 #endif
235 };
236
237 struct wcd *wcdtab[NUNIT]; /* Drive info by unit number */
238 static int wcdnlun = 0; /* Number of configured drives */
239
240 static void wcd_start (struct wcd *t);
241 static void wcd_done (struct wcd *t, struct buf *bp, int resid,
242 struct atapires result);
243 static void wcd_error (struct wcd *t, struct atapires result);
244 static int wcd_read_toc (struct wcd *t);
245 static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
246 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
247 u_char a9, char *addr, int count);
248 static void wcd_describe (struct wcd *t);
249 static int wcd_open(dev_t dev, int rawflag);
250 static int wcd_setchan (struct wcd *t,
251 u_char c0, u_char c1, u_char c2, u_char c3);
252 static int wcd_eject (struct wcd *t, int closeit);
253
254 /*
255 * Dump the array in hexadecimal format for debugging purposes.
256 */
257 static void wcd_dump (int lun, char *label, void *data, int len)
258 {
259 u_char *p = data;
260
261 printf ("wcd%d: %s %x", lun, label, *p++);
262 while (--len > 0)
263 printf ("-%x", *p++);
264 printf ("\n");
265 }
266
267 #ifndef ATAPI_STATIC
268 static
269 #endif
270 int
271 wcdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
272 {
273 struct wcd *t;
274 struct atapires result;
275 int lun;
276
277 if (wcdnlun >= NUNIT) {
278 printf ("wcd: too many units\n");
279 return (0);
280 }
281 if (!atapi_request_immediate) {
282 printf("wcd: configuration error, ATAPI core code not present!\n");
283 printf("wcd: check `options ATAPI_STATIC' in your kernel config file!\n");
284 return (0);
285 }
286 t = malloc (sizeof (struct wcd), M_TEMP, M_NOWAIT);
287 if (! t) {
288 printf ("wcd: out of memory\n");
289 return (0);
290 }
291 wcdtab[wcdnlun] = t;
292 bzero (t, sizeof (struct wcd));
293 bufq_init(&t->buf_queue);
294 t->ata = ata;
295 t->unit = unit;
296 lun = t->lun = wcdnlun++;
297 t->param = ap;
298 t->flags = F_MEDIA_CHANGED;
299 t->starting_lba = 0;
300 t->refcnt = 0;
301 if (debug) {
302 t->flags |= F_DEBUG;
303 /* Print params. */
304 wcd_dump (t->lun, "info", ap, sizeof *ap);
305 }
306
307 /* Get drive capabilities. */
308 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
309 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8, sizeof (t->cap),
310 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
311
312 /* Do it twice to avoid the stale media changed state. */
313 if (result.code == RES_ERR &&
314 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
315 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
316 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
317 sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
318 (char*) &t->cap, sizeof (t->cap));
319
320 /* Some drives have shorter capabilities page. */
321 if (result.code == RES_UNDERRUN)
322 result.code = 0;
323
324 if (result.code == 0) {
325 wcd_describe (t);
326 if (t->flags & F_DEBUG)
327 wcd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
328 }
329
330
331 #ifdef DEVFS
332 t->ra_devfs_token =
333 devfs_add_devswf(&wcd_cdevsw, dkmakeminor(lun, 0, 0),
334 DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
335 "rwcd%da", lun);
336 t->rc_devfs_token =
337 devfs_add_devswf(&wcd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
338 DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
339 "rwcd%dc", lun);
340 t->a_devfs_token =
341 devfs_add_devswf(&wcd_bdevsw, dkmakeminor(lun, 0, 0),
342 DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
343 "wcd%da", lun);
344 t->c_devfs_token =
345 devfs_add_devswf(&wcd_bdevsw, dkmakeminor(lun, 0, RAW_PART),
346 DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
347 "wcd%dc", lun);
348 #endif
349 return (1);
350 }
351
352 void wcd_describe (struct wcd *t)
353 {
354 char *m;
355
356 t->cap.max_speed = ntohs (t->cap.max_speed);
357 t->cap.max_vol_levels = ntohs (t->cap.max_vol_levels);
358 t->cap.buf_size = ntohs (t->cap.buf_size);
359 t->cap.cur_speed = ntohs (t->cap.cur_speed);
360
361 printf ("wcd%d: ", t->lun);
362 if (t->cap.cur_speed != t->cap.max_speed)
363 printf ("%d/", t->cap.cur_speed * 1000 / 1024);
364 printf ("%dKB/sec", t->cap.max_speed * 1000 / 1024);
365 if (t->cap.buf_size)
366 printf (", %dKB cache", t->cap.buf_size);
367
368 if (t->cap.audio_play)
369 printf (", audio play");
370 if (t->cap.max_vol_levels)
371 printf (", %d volume levels", t->cap.max_vol_levels);
372
373 switch (t->cap.mech) {
374 default: m = 0; break;
375 case MECH_CADDY: m = "caddy"; break;
376 case MECH_TRAY: m = "tray"; break;
377 case MECH_POPUP: m = "popup"; break;
378 case MECH_CHANGER: m = "changer"; break;
379 case MECH_CARTRIDGE: m = "cartridge"; break;
380 }
381 if (m)
382 printf (", %s%s", t->cap.eject ? "ejectable " : "", m);
383 else if (t->cap.eject)
384 printf (", eject");
385 printf ("\n");
386
387 printf ("wcd%d: ", t->lun);
388 switch (t->cap.medium_type) {
389 case MDT_UNKNOWN: printf ("medium type unknown"); break;
390 case MDT_DATA_120: printf ("120mm data disc loaded"); break;
391 case MDT_AUDIO_120: printf ("120mm audio disc loaded"); break;
392 case MDT_COMB_120: printf ("120mm data/audio disc loaded"); break;
393 case MDT_PHOTO_120: printf ("120mm photo disc loaded"); break;
394 case MDT_DATA_80: printf ("80mm data disc loaded"); break;
395 case MDT_AUDIO_80: printf ("80mm audio disc loaded"); break;
396 case MDT_COMB_80: printf ("80mm data/audio disc loaded"); break;
397 case MDT_PHOTO_80: printf ("80mm photo disc loaded"); break;
398 case MDT_NO_DISC: printf ("no disc inside"); break;
399 case MDT_DOOR_OPEN: printf ("door open"); break;
400 case MDT_FMT_ERROR: printf ("medium format error"); break;
401 default: printf ("medium type=0x%x", t->cap.medium_type); break;
402 }
403 if (t->cap.lock)
404 printf (t->cap.locked ? ", locked" : ", unlocked");
405 if (t->cap.prevent)
406 printf (", lock protected");
407 printf ("\n");
408 }
409
410 static int
411 wcd_open (dev_t dev, int rawflag)
412 {
413 int lun = UNIT(dev);
414 int track = dkslice(dev); /* XXX */
415 struct wcd *t;
416
417 /* Check that the device number is legal
418 * and the ATAPI driver is loaded. */
419 if (lun >= wcdnlun || ! atapi_request_immediate)
420 return (ENXIO);
421 t = wcdtab[lun];
422
423 /* On the first open, read the table of contents. */
424 if (! (t->flags & F_BOPEN) && ! t->refcnt) {
425 /* Read table of contents. */
426 if (wcd_read_toc (t) < 0)
427 return (EIO);
428
429 /* Lock the media. */
430 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
431 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
432 }
433 if (rawflag)
434 ++t->refcnt;
435 else
436 t->flags |= F_BOPEN;
437 t->starting_lba = ntohl(t->toc.tab[track].addr.lba) ;
438 if (track != 0) {
439 printf("Warning, opening track %d at %d\n",
440 track, t->starting_lba);
441 }
442 return (0);
443 }
444
445 int wcdbopen (dev_t dev, int flags, int fmt, struct proc *p)
446 {
447 return wcd_open (dev, 0);
448 }
449
450 int wcdropen (dev_t dev, int flags, int fmt, struct proc *p)
451 {
452 return wcd_open (dev, 1);
453 }
454
455 /*
456 * Close the device. Only called if we are the LAST
457 * occurence of an open device.
458 */
459 int wcdbclose (dev_t dev, int flags, int fmt, struct proc *p)
460 {
461 int lun = UNIT(dev);
462 struct wcd *t = wcdtab[lun];
463
464 /* If we were the last open of the entire device, release it. */
465 if (! t->refcnt)
466 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
468 t->flags &= ~F_BOPEN;
469 return (0);
470 }
471
472 int wcdrclose (dev_t dev, int flags, int fmt, struct proc *p)
473 {
474 int lun = UNIT(dev);
475 struct wcd *t = wcdtab[lun];
476
477 /* If we were the last open of the entire device, release it. */
478 if (! (t->flags & F_BOPEN) && t->refcnt == 1)
479 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
481 --t->refcnt;
482 return (0);
483 }
484
485 /*
486 * Actually translate the requested transfer into one the physical driver can
487 * understand. The transfer is described by a buf and will include only one
488 * physical transfer.
489 */
490 void wcdstrategy (struct buf *bp)
491 {
492 int lun = UNIT(bp->b_dev);
493 struct wcd *t = wcdtab[lun];
494 int x;
495
496 /* Can't ever write to a CD. */
497 if (! (bp->b_flags & B_READ)) {
498 bp->b_error = EROFS;
499 bp->b_flags |= B_ERROR;
500 biodone (bp);
501 return;
502 }
503
504 /* If it's a null transfer, return immediatly. */
505 if (bp->b_bcount == 0) {
506 bp->b_resid = 0;
507 biodone (bp);
508 return;
509 }
510
511 /* Process transfer request. */
512 bp->b_pblkno = bp->b_blkno;
513 bp->b_resid = bp->b_bcount;
514
515 x = splbio();
516
517 /* Place it in the queue of disk activities for this disk. */
518 bufqdisksort (&t->buf_queue, bp);
519
520 /* Tell the device to get going on the transfer if it's
521 * not doing anything, otherwise just wait for completion. */
522 wcd_start (t);
523 splx(x);
524 }
525
526 /*
527 * Look to see if there is a buf waiting for the device
528 * and that the device is not already busy. If both are true,
529 * It dequeues the buf and creates an ATAPI command to perform the
530 * transfer in the buf.
531 * The bufs are queued by the strategy routine (wcdstrategy).
532 * Must be called at the correct (splbio) level.
533 */
534 static void wcd_start (struct wcd *t)
535 {
536 struct buf *bp = bufq_first(&t->buf_queue);
537 u_long blkno, nblk;
538
539 /* See if there is a buf to do and we are not already doing one. */
540 if (! bp)
541 return;
542
543 /* Unqueue the request. */
544 bufq_remove(&t->buf_queue, bp);
545
546 /* Should reject all queued entries if media have changed. */
547 if (t->flags & F_MEDIA_CHANGED) {
548 bp->b_error = EIO;
549 bp->b_flags |= B_ERROR;
550 biodone (bp);
551 return;
552 }
553
554 /* We have a buf, now we should make a command
555 * First, translate the block to absolute and put it in terms of the
556 * logical blocksize of the device.
557 * What if something asks for 512 bytes not on a 2k boundary? */
558 blkno = t->starting_lba + bp->b_blkno / (SECSIZE / 512);
559 nblk = (bp->b_bcount + (SECSIZE - 1)) / SECSIZE;
560
561 atapi_request_callback (t->ata, t->unit, ATAPI_READ_BIG, 0,
562 blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
563 0, 0, 0, 0, 0, (u_char*) bp->b_un.b_addr, bp->b_bcount,
564 wcd_done, t, bp);
565 }
566
567 static void wcd_done (struct wcd *t, struct buf *bp, int resid,
568 struct atapires result)
569 {
570 if (result.code) {
571 wcd_error (t, result);
572 bp->b_error = EIO;
573 bp->b_flags |= B_ERROR;
574 } else
575 bp->b_resid = resid;
576 biodone (bp);
577 wcd_start (t);
578 }
579
580 static void wcd_error (struct wcd *t, struct atapires result)
581 {
582 if (result.code != RES_ERR)
583 return;
584 switch (result.error & AER_SKEY) {
585 case AER_SK_NOT_READY:
586 if (result.error & ~AER_SKEY) {
587 /* Audio disc. */
588 printf ("wcd%d: cannot read audio disc\n", t->lun);
589 return;
590 }
591 /* Tray open. */
592 if (! (t->flags & F_MEDIA_CHANGED))
593 printf ("wcd%d: tray open\n", t->lun);
594 t->flags |= F_MEDIA_CHANGED;
595 return;
596
597 case AER_SK_UNIT_ATTENTION:
598 /* Media changed. */
599 if (! (t->flags & F_MEDIA_CHANGED))
600 printf ("wcd%d: media changed\n", t->lun);
601 t->flags |= F_MEDIA_CHANGED;
602 return;
603
604 case AER_SK_ILLEGAL_REQUEST:
605 /* Unknown command or invalid command arguments. */
606 if (t->flags & F_DEBUG)
607 printf ("wcd%d: invalid command\n", t->lun);
608 return;
609 }
610 printf ("wcd%d: i/o error, status=%b, error=%b\n", t->lun,
611 result.status, ARS_BITS, result.error, AER_BITS);
612 }
613
614 static int wcd_request_wait (struct wcd *t, u_char cmd, u_char a1, u_char a2,
615 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
616 u_char a9, char *addr, int count)
617 {
618 struct atapires result;
619
620 result = atapi_request_wait (t->ata, t->unit, cmd,
621 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
622 addr, count);
623 if (result.code) {
624 wcd_error (t, result);
625 return (EIO);
626 }
627 return (0);
628 }
629
630 static __inline void lba2msf (int lba, u_char *m, u_char *s, u_char *f)
631 {
632 lba += 150; /* offset of first logical frame */
633 lba &= 0xffffff; /* negative lbas use only 24 bits */
634 *m = lba / (60 * 75);
635 lba %= (60 * 75);
636 *s = lba / 75;
637 *f = lba % 75;
638 }
639
640 /*
641 * Perform special action on behalf of the user.
642 * Knows about the internals of this device
643 */
644 int wcdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
645 {
646 int lun = UNIT(dev);
647 struct wcd *t = wcdtab[lun];
648 int error = 0;
649
650 if (t->flags & F_MEDIA_CHANGED)
651 switch (cmd) {
652 case CDIOCSETDEBUG:
653 case CDIOCCLRDEBUG:
654 case CDIOCRESET:
655 /* These ops are media change transparent. */
656 break;
657 default:
658 /* Read table of contents. */
659 wcd_read_toc (t);
660
661 /* Lock the media. */
662 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
663 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
664 break;
665 }
666 switch (cmd) {
667 default:
668 return (ENOTTY);
669
670 case CDIOCSETDEBUG:
671 if (p->p_cred->pc_ucred->cr_uid)
672 return (EPERM);
673 t->flags |= F_DEBUG;
674 atapi_debug (t->ata, 1);
675 return 0;
676
677 case CDIOCCLRDEBUG:
678 if (p->p_cred->pc_ucred->cr_uid)
679 return (EPERM);
680 t->flags &= ~F_DEBUG;
681 atapi_debug (t->ata, 0);
682 return 0;
683
684 case CDIOCRESUME:
685 return wcd_request_wait (t, ATAPI_PAUSE,
686 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
687
688 case CDIOCPAUSE:
689 return wcd_request_wait (t, ATAPI_PAUSE,
690 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
691
692 case CDIOCSTART:
693 return wcd_request_wait (t, ATAPI_START_STOP,
694 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
695
696 case CDIOCSTOP:
697 return wcd_request_wait (t, ATAPI_START_STOP,
698 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
699
700 case CDIOCALLOW:
701 return wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
702 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
703
704 case CDIOCPREVENT:
705 return wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
706 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
707
708 case CDIOCRESET:
709 if (p->p_cred->pc_ucred->cr_uid)
710 return (EPERM);
711 return wcd_request_wait (t, ATAPI_TEST_UNIT_READY,
712 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
713
714 case CDIOCEJECT:
715 /* Don't allow eject if the device is opened
716 * by somebody (not us) in block mode. */
717 if ((t->flags & F_BOPEN) && t->refcnt)
718 return (EBUSY);
719 return wcd_eject (t, 0);
720
721 case CDIOCCLOSE:
722 if ((t->flags & F_BOPEN) && t->refcnt)
723 return (0);
724 return wcd_eject (t, 1);
725
726 case CDIOREADTOCHEADER:
727 if (! t->toc.hdr.ending_track)
728 return (EIO);
729 bcopy (&t->toc.hdr, addr, sizeof t->toc.hdr);
730 break;
731
732 case CDIOREADTOCENTRYS: {
733 struct ioc_read_toc_entry *te =
734 (struct ioc_read_toc_entry*) addr;
735 struct toc *toc = &t->toc;
736 struct toc buf;
737 u_long len;
738 u_char starting_track = te->starting_track;
739
740 if (! t->toc.hdr.ending_track)
741 return (EIO);
742
743 if ( te->data_len < sizeof(toc->tab[0])
744 || (te->data_len % sizeof(toc->tab[0])) != 0
745 || te->address_format != CD_MSF_FORMAT
746 && te->address_format != CD_LBA_FORMAT
747 )
748 return EINVAL;
749
750 if (starting_track == 0)
751 starting_track = toc->hdr.starting_track;
752 else if (starting_track == 170) /* Handle leadout request */
753 starting_track = toc->hdr.ending_track + 1;
754 else if (starting_track < toc->hdr.starting_track ||
755 starting_track > toc->hdr.ending_track + 1)
756 return (EINVAL);
757
758 len = ((toc->hdr.ending_track + 1 - starting_track) + 1) *
759 sizeof(toc->tab[0]);
760 if (te->data_len < len)
761 len = te->data_len;
762 if (len > sizeof(toc->tab))
763 return EINVAL;
764
765 /* Convert to MSF format, if needed. */
766 if (te->address_format == CD_MSF_FORMAT) {
767 struct cd_toc_entry *e;
768
769 buf = t->toc;
770 toc = &buf;
771 e = toc->tab + (toc->hdr.ending_track + 1 -
772 toc->hdr.starting_track) + 1;
773 while (--e >= toc->tab)
774 lba2msf (ntohl(e->addr.lba), &e->addr.msf.minute,
775 &e->addr.msf.second, &e->addr.msf.frame);
776 }
777 return copyout (toc->tab + starting_track -
778 toc->hdr.starting_track, te->data, len);
779 }
780 case CDIOCREADSUBCHANNEL: {
781 struct ioc_read_subchannel *args =
782 (struct ioc_read_subchannel*) addr;
783 struct cd_sub_channel_info data;
784 u_long len = args->data_len;
785 int abslba, rellba;
786
787 if (len > sizeof(data) ||
788 len < sizeof(struct cd_sub_channel_header))
789 return (EINVAL);
790
791 if (wcd_request_wait (t, ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0,
792 0, 0, sizeof (t->subchan) >> 8, sizeof (t->subchan),
793 0, (char*)&t->subchan, sizeof (t->subchan)) != 0)
794 return (EIO);
795 if (t->flags & F_DEBUG)
796 wcd_dump (t->lun, "subchan", &t->subchan, sizeof t->subchan);
797
798 abslba = t->subchan.abslba;
799 rellba = t->subchan.rellba;
800 if (args->address_format == CD_MSF_FORMAT) {
801 lba2msf (ntohl(abslba),
802 &data.what.position.absaddr.msf.minute,
803 &data.what.position.absaddr.msf.second,
804 &data.what.position.absaddr.msf.frame);
805 lba2msf (ntohl(rellba),
806 &data.what.position.reladdr.msf.minute,
807 &data.what.position.reladdr.msf.second,
808 &data.what.position.reladdr.msf.frame);
809 } else {
810 data.what.position.absaddr.lba = abslba;
811 data.what.position.reladdr.lba = rellba;
812 }
813 data.header.audio_status = t->subchan.audio_status;
814 data.what.position.control = t->subchan.control & 0xf;
815 data.what.position.addr_type = t->subchan.control >> 4;
816 data.what.position.track_number = t->subchan.track;
817 data.what.position.index_number = t->subchan.indx;
818
819 return copyout (&data, args->data, len);
820 }
821 case CDIOCPLAYMSF: {
822 struct ioc_play_msf *args = (struct ioc_play_msf*) addr;
823
824 return wcd_request_wait (t, ATAPI_PLAY_MSF, 0, 0,
825 args->start_m, args->start_s, args->start_f,
826 args->end_m, args->end_s, args->end_f, 0, 0, 0);
827 }
828 case CDIOCPLAYBLOCKS: {
829 struct ioc_play_blocks *args = (struct ioc_play_blocks*) addr;
830
831 return wcd_request_wait (t, ATAPI_PLAY_BIG, 0,
832 args->blk >> 24 & 0xff, args->blk >> 16 & 0xff,
833 args->blk >> 8 & 0xff, args->blk & 0xff,
834 args->len >> 24 & 0xff, args->len >> 16 & 0xff,
835 args->len >> 8 & 0xff, args->len & 0xff, 0, 0);
836 }
837 case CDIOCPLAYTRACKS: {
838 struct ioc_play_track *args = (struct ioc_play_track*) addr;
839 u_long start, len;
840 int t1, t2;
841
842 if (! t->toc.hdr.ending_track)
843 return (EIO);
844
845 /* Ignore index fields,
846 * play from start_track to end_track inclusive. */
847 if (args->end_track < t->toc.hdr.ending_track+1)
848 ++args->end_track;
849 if (args->end_track > t->toc.hdr.ending_track+1)
850 args->end_track = t->toc.hdr.ending_track+1;
851 t1 = args->start_track - t->toc.hdr.starting_track;
852 t2 = args->end_track - t->toc.hdr.starting_track;
853 if (t1 < 0 || t2 < 0)
854 return (EINVAL);
855 start = ntohl(t->toc.tab[t1].addr.lba);
856 len = ntohl(t->toc.tab[t2].addr.lba) - start;
857
858 return wcd_request_wait (t, ATAPI_PLAY_BIG, 0,
859 start >> 24 & 0xff, start >> 16 & 0xff,
860 start >> 8 & 0xff, start & 0xff,
861 len >> 24 & 0xff, len >> 16 & 0xff,
862 len >> 8 & 0xff, len & 0xff, 0, 0);
863 }
864 case CDIOCGETVOL: {
865 struct ioc_vol *arg = (struct ioc_vol*) addr;
866
867 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
868 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
869 (char*) &t->au, sizeof (t->au));
870 if (error)
871 return (error);
872 if (t->flags & F_DEBUG)
873 wcd_dump (t->lun, "au", &t->au, sizeof t->au);
874 if (t->au.page_code != AUDIO_PAGE)
875 return (EIO);
876 arg->vol[0] = t->au.port[0].volume;
877 arg->vol[1] = t->au.port[1].volume;
878 arg->vol[2] = t->au.port[2].volume;
879 arg->vol[3] = t->au.port[3].volume;
880 break;
881 }
882 case CDIOCSETVOL: {
883 struct ioc_vol *arg = (struct ioc_vol*) addr;
884
885 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
886 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
887 (char*) &t->au, sizeof (t->au));
888 if (error)
889 return (error);
890 if (t->flags & F_DEBUG)
891 wcd_dump (t->lun, "au", &t->au, sizeof t->au);
892 if (t->au.page_code != AUDIO_PAGE)
893 return (EIO);
894
895 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0,
896 AUDIO_PAGE_MASK, 0, 0, 0, 0, sizeof (t->aumask) >> 8,
897 sizeof (t->aumask), 0, (char*) &t->aumask,
898 sizeof (t->aumask));
899 if (error)
900 return (error);
901 if (t->flags & F_DEBUG)
902 wcd_dump (t->lun, "mask", &t->aumask, sizeof t->aumask);
903
904 /* Sony-55E requires the data length field to be zeroed. */
905 t->au.data_length = 0;
906
907 t->au.port[0].channels = CHANNEL_0;
908 t->au.port[1].channels = CHANNEL_1;
909 t->au.port[0].volume = arg->vol[0] & t->aumask.port[0].volume;
910 t->au.port[1].volume = arg->vol[1] & t->aumask.port[1].volume;
911 t->au.port[2].volume = arg->vol[2] & t->aumask.port[2].volume;
912 t->au.port[3].volume = arg->vol[3] & t->aumask.port[3].volume;
913 return wcd_request_wait (t, ATAPI_MODE_SELECT_BIG, 0x10,
914 0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
915 0, (char*) &t->au, - sizeof (t->au));
916 }
917 case CDIOCSETPATCH: {
918 struct ioc_patch *arg = (struct ioc_patch*) addr;
919
920 return wcd_setchan (t, arg->patch[0], arg->patch[1],
921 arg->patch[2], arg->patch[3]);
922 }
923 case CDIOCSETMONO:
924 return wcd_setchan (t, CHANNEL_0 | CHANNEL_1,
925 CHANNEL_0 | CHANNEL_1, 0, 0);
926
927 case CDIOCSETSTERIO:
928 return wcd_setchan (t, CHANNEL_0, CHANNEL_1, 0, 0);
929
930 case CDIOCSETMUTE:
931 return wcd_setchan (t, 0, 0, 0, 0);
932
933 case CDIOCSETLEFT:
934 return wcd_setchan (t, CHANNEL_0, CHANNEL_0, 0, 0);
935
936 case CDIOCSETRIGHT:
937 return wcd_setchan (t, CHANNEL_1, CHANNEL_1, 0, 0);
938 }
939 return (error);
940 }
941
942 /*
943 * Read the entire TOC for the disc into our internal buffer.
944 */
945 static int wcd_read_toc (struct wcd *t)
946 {
947 int ntracks, len;
948 struct atapires result;
949
950 bzero (&t->toc, sizeof (t->toc));
951 bzero (&t->info, sizeof (t->info));
952
953 /* Check for the media.
954 * Do it twice to avoid the stale media changed state. */
955 result = atapi_request_wait (t->ata, t->unit, ATAPI_TEST_UNIT_READY,
956 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
957
958 if (result.code == RES_ERR &&
959 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
960 t->flags |= F_MEDIA_CHANGED;
961 result = atapi_request_wait (t->ata, t->unit,
962 ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0,
963 0, 0, 0, 0, 0, 0, 0, 0, 0);
964 }
965 if (result.code) {
966 wcd_error (t, result);
967 return (EIO);
968 }
969 t->flags &= ~F_MEDIA_CHANGED;
970
971 /* First read just the header, so we know how long the TOC is. */
972 len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
973 if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
974 len >> 8, len & 0xff, 0, (char*)&t->toc, len) != 0) {
975 err: bzero (&t->toc, sizeof (t->toc));
976 return (0);
977 }
978
979 ntracks = t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1;
980 if (ntracks <= 0 || ntracks > MAXTRK)
981 goto err;
982
983 /* Now read the whole schmeer. */
984 len = sizeof(struct ioc_toc_header) +
985 ntracks * sizeof(struct cd_toc_entry);
986 if (wcd_request_wait (t, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
987 len >> 8, len & 0xff, 0, (char*)&t->toc, len) & 0xff)
988 goto err;
989
990 NTOHS(t->toc.hdr.len);
991
992 /* Read disc capacity. */
993 if (wcd_request_wait (t, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0,
994 0, sizeof(t->info), 0, (char*)&t->info, sizeof(t->info)) != 0)
995 bzero (&t->info, sizeof (t->info));
996
997 /* make fake leadout entry */
998 t->toc.tab[ntracks].control = t->toc.tab[ntracks-1].control;
999 t->toc.tab[ntracks].addr_type = t->toc.tab[ntracks-1].addr_type;
1000 t->toc.tab[ntracks].track = 170; /* magic */
1001 t->toc.tab[ntracks].addr.lba = t->info.volsize;
1002
1003 NTOHL(t->info.volsize);
1004 NTOHL(t->info.blksize);
1005
1006 /* Print the disc description string on every disc change.
1007 * It would help to track the history of disc changes. */
1008 if (t->info.volsize && t->toc.hdr.ending_track &&
1009 (t->flags & F_MEDIA_CHANGED) && (t->flags & F_DEBUG)) {
1010 printf ("wcd%d: ", t->lun);
1011 if (t->toc.tab[0].control & 4)
1012 printf ("%ldMB ", t->info.volsize / 512);
1013 else
1014 printf ("%ld:%ld audio ", t->info.volsize/75/60,
1015 t->info.volsize/75%60);
1016 printf ("(%ld sectors), %d tracks\n", t->info.volsize,
1017 t->toc.hdr.ending_track - t->toc.hdr.starting_track + 1);
1018 }
1019 return (0);
1020 }
1021
1022 /*
1023 * Set up the audio channel masks.
1024 */
1025 static int wcd_setchan (struct wcd *t,
1026 u_char c0, u_char c1, u_char c2, u_char c3)
1027 {
1028 int error;
1029
1030 error = wcd_request_wait (t, ATAPI_MODE_SENSE, 0, AUDIO_PAGE,
1031 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au), 0,
1032 (char*) &t->au, sizeof (t->au));
1033 if (error)
1034 return (error);
1035 if (t->flags & F_DEBUG)
1036 wcd_dump (t->lun, "au", &t->au, sizeof t->au);
1037 if (t->au.page_code != AUDIO_PAGE)
1038 return (EIO);
1039
1040 /* Sony-55E requires the data length field to be zeroed. */
1041 t->au.data_length = 0;
1042
1043 t->au.port[0].channels = c0;
1044 t->au.port[1].channels = c1;
1045 t->au.port[2].channels = c2;
1046 t->au.port[3].channels = c3;
1047 return wcd_request_wait (t, ATAPI_MODE_SELECT_BIG, 0x10,
1048 0, 0, 0, 0, 0, sizeof (t->au) >> 8, sizeof (t->au),
1049 0, (char*) &t->au, - sizeof (t->au));
1050 }
1051
1052 static int wcd_eject (struct wcd *t, int closeit)
1053 {
1054 struct atapires result;
1055
1056 /* Try to stop the disc. */
1057 result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
1058 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1059
1060 if (result.code == RES_ERR &&
1061 ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
1062 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
1063 int err;
1064
1065 if (!closeit)
1066 return (0);
1067 /*
1068 * The disc was unloaded.
1069 * Load it (close tray).
1070 * Read the table of contents.
1071 */
1072 err = wcd_request_wait (t, ATAPI_START_STOP,
1073 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
1074 if (err)
1075 return (err);
1076
1077 /* Read table of contents. */
1078 wcd_read_toc (t);
1079
1080 /* Lock the media. */
1081 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
1082 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
1083
1084 return (0);
1085 }
1086
1087 if (result.code) {
1088 wcd_error (t, result);
1089 return (EIO);
1090 }
1091
1092 if (closeit)
1093 return (0);
1094
1095 /* Give it some time to stop spinning. */
1096 tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej1", 0);
1097 tsleep ((caddr_t)&lbolt, PRIBIO, "wcdej2", 0);
1098
1099 /* Unlock. */
1100 wcd_request_wait (t, ATAPI_PREVENT_ALLOW,
1101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1102
1103 /* Eject. */
1104 t->flags |= F_MEDIA_CHANGED;
1105 return wcd_request_wait (t, ATAPI_START_STOP,
1106 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
1107 }
1108
1109 #ifdef WCD_MODULE
1110 /*
1111 * Loadable ATAPI CD-ROM driver stubs.
1112 */
1113 #include <sys/exec.h>
1114 #include <sys/sysent.h>
1115 #include <sys/lkm.h>
1116
1117 /*
1118 * Construct lkm_dev structures (see lkm.h).
1119 * Our bdevsw/cdevsw slot numbers are 19/69.
1120 */
1121
1122
1123 MOD_DEV(wcd, LM_DT_BLOCK, BDEV_MAJOR, &wcd_bdevsw);
1124 MOD_DEV(rwcd, LM_DT_CHAR, CDEV_MAJOR, &wcd_cdevsw);
1125
1126 /*
1127 * Function called when loading the driver.
1128 */
1129 int wcd_load (struct lkm_table *lkmtp, int cmd)
1130 {
1131 struct atapi *ata;
1132 int n, u;
1133
1134 if (! atapi_start)
1135 /* No ATAPI driver available. */
1136 return EPROTONOSUPPORT;
1137 n = 0;
1138 for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
1139 if (ata->port)
1140 for (u=0; u<2; ++u)
1141 /* Probing controller ata->ctrlr, unit u. */
1142 if (ata->params[u] && ! ata->attached[u] &&
1143 wcdattach (ata, u, ata->params[u],
1144 ata->debug) >= 0)
1145 {
1146 /* Drive found. */
1147 ata->attached[u] = 1;
1148 ++n;
1149 }
1150 if (! n)
1151 /* No IDE CD-ROMs found. */
1152 return ENXIO;
1153 return 0;
1154 }
1155
1156 /*
1157 * Function called when unloading the driver.
1158 */
1159 int wcd_unload (struct lkm_table *lkmtp, int cmd)
1160 {
1161 struct wcd **t;
1162
1163 for (t=wcdtab; t<wcdtab+wcdnlun; ++t)
1164 if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
1165 /* The device is opened, cannot unload the driver. */
1166 return EBUSY;
1167 for (t=wcdtab; t<wcdtab+wcdnlun; ++t) {
1168 (*t)->ata->attached[(*t)->unit] = 0;
1169 free (*t, M_TEMP);
1170 }
1171 wcdnlun = 0;
1172 bzero (wcdtab, sizeof(wcdtab));
1173 return 0;
1174 }
1175
1176 /*
1177 * Dispatcher function for the module (load/unload/stat).
1178 */
1179 int wcd_mod (struct lkm_table *lkmtp, int cmd, int ver)
1180 {
1181 int err = 0;
1182
1183 if (ver != LKM_VERSION)
1184 return EINVAL;
1185
1186 if (cmd == LKM_E_LOAD)
1187 err = wcd_load (lkmtp, cmd);
1188 else if (cmd == LKM_E_UNLOAD)
1189 err = wcd_unload (lkmtp, cmd);
1190 if (err)
1191 return err;
1192
1193 /* Register the cdevsw entry. */
1194 lkmtp->private.lkm_dev = &rwcd_module;
1195 err = lkmdispatch (lkmtp, cmd);
1196 if (err)
1197 return err;
1198
1199 /* Register the bdevsw entry. */
1200 lkmtp->private.lkm_dev = &wcd_module;
1201 return lkmdispatch (lkmtp, cmd);
1202 }
1203 #endif /* WCD_MODULE */
1204
1205 static wcd_devsw_installed = 0;
1206
1207 static void wcd_drvinit(void *unused)
1208 {
1209 dev_t dev;
1210
1211 if( ! wcd_devsw_installed ) {
1212 dev = makedev(CDEV_MAJOR, 0);
1213 cdevsw_add(&dev,&wcd_cdevsw, NULL);
1214 dev = makedev(BDEV_MAJOR, 0);
1215 bdevsw_add(&dev,&wcd_bdevsw, NULL);
1216 wcd_devsw_installed = 1;
1217 }
1218 }
1219
1220 SYSINIT(wcddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wcd_drvinit,NULL)
1221
1222
1223 #endif /* NWCD && NWDC && ATAPI */
Cache object: 6df796e94fb94dc80daf8d72a9a6ff97
|