FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/wd_cd.c
1 /*-
2 * Copyright (c) 1998, 1999 Søren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/proc.h>
35 #include <sys/malloc.h>
36 #include <sys/buf.h>
37 #include <sys/disklabel.h>
38 #include <sys/devicestat.h>
39 #include <sys/cdio.h>
40 #include <sys/wormio.h>
41 #include <sys/fcntl.h>
42 #include <sys/conf.h>
43 #include <sys/stat.h>
44 #include <i386/isa/atapi.h>
45 #include <i386/isa/wd_cd.h>
46
47 static d_open_t acdopen;
48 static d_close_t acdclose;
49 static d_ioctl_t acdioctl;
50 static d_strategy_t acdstrategy;
51
52 #define CDEV_MAJOR 69
53 #define BDEV_MAJOR 19
54 static struct cdevsw acd_cdevsw = {
55 /* open */ acdopen,
56 /* close */ acdclose,
57 /* read */ physread,
58 /* write */ physwrite,
59 /* ioctl */ acdioctl,
60 /* poll */ nopoll,
61 /* mmap */ nommap,
62 /* strategy */ acdstrategy,
63 /* name */ "wcd",
64 /* maj */ CDEV_MAJOR,
65 /* dump */ nodump,
66 /* psize */ nopsize,
67 /* flags */ D_DISK,
68 /* bmaj */ BDEV_MAJOR
69 };
70
71 #define NUNIT 16 /* Max # of devices */
72
73 #define F_BOPEN 0x0001 /* The block device is opened */
74 #define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
75 #define F_DEBUG 0x0004 /* Print debug info */
76 #define F_LOCKED 0x0008 /* This unit is locked (or should be) */
77 #define F_TRACK_PREP 0x0010 /* Track should be prep'ed */
78 #define F_TRACK_PREPED 0x0020 /* Track has been prep'ed */
79 #define F_DISK_PREPED 0x0040 /* Disk has been prep'ed */
80 #define F_WRITTEN 0x0080 /* The medium has been written to */
81
82 static struct acd *acdtab[NUNIT];
83 static int acdnlun = 0; /* Number of configured drives */
84
85 int acdattach(struct atapi *, int, struct atapi_params *, int);
86 static struct acd *acd_init_lun(struct atapi *, int, struct atapi_params *, int,
87 struct devstat *);
88 static void acd_start(struct acd *);
89 static void acd_done(struct acd *, struct buf *, int, struct atapires);
90 static int acd_read_toc(struct acd *);
91 static int acd_request_wait(struct acd *, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, u_char, char *, int);
92 static void acd_describe(struct acd *);
93 static int acd_setchan(struct acd *, u_char, u_char, u_char, u_char);
94 static int acd_eject(struct acd *, int);
95 static void acd_select_slot(struct acd *);
96 static int acd_open_disk(struct acd *, int);
97 static int acd_open_track(struct acd *, struct wormio_prepare_track *);
98 static int acd_close_track(struct acd *);
99 static int acd_close_disk(struct acd *);
100 static int acd_read_track_info(struct acd *cdp, int lba, struct acd_track_info *info);
101 static int acd_blank_disk(struct acd *);
102 static void atapi_dump(int ctrlr, int lun, char *label, void *data, int len);
103 static void atapi_error(struct atapi *ata, int unit, struct atapires result);
104
105 struct acd *
106 acd_init_lun(struct atapi *ata, int unit, struct atapi_params *ap, int lun,
107 struct devstat *device_stats)
108 {
109 struct acd *ptr;
110
111 if (!(ptr = malloc(sizeof(struct acd), M_TEMP, M_NOWAIT)))
112 return NULL;
113 bzero(ptr, sizeof(struct acd));
114 bufq_init(&ptr->buf_queue);
115 ptr->ata = ata;
116 ptr->unit = unit;
117 ptr->lun = lun;
118 ptr->param = ap;
119 ptr->flags = F_MEDIA_CHANGED;
120 ptr->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
121 ptr->block_size = 2048;
122 ptr->refcnt = 0;
123 ptr->slot = -1;
124 ptr->changer_info = NULL;
125 if (device_stats == NULL) {
126 if (!(ptr->device_stats = malloc(sizeof(struct devstat),
127 M_TEMP, M_NOWAIT)))
128 return NULL;
129 bzero(ptr->device_stats, sizeof(struct devstat));
130 }
131 else
132 ptr->device_stats = device_stats;
133 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0),
134 UID_ROOT, GID_OPERATOR, 0640, "rwcd%da", lun);
135 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
136 UID_ROOT, GID_OPERATOR, 0640, "rwcd%dc", lun);
137 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0),
138 UID_ROOT, GID_OPERATOR, 0640, "wcd%da", lun);
139 make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
140 UID_ROOT, GID_OPERATOR, 0640, "wcd%dc", lun);
141 return ptr;
142 }
143
144 int
145 acdattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
146 {
147 struct acd *cdp;
148 struct atapires result;
149 struct changer *chp;
150 int i, count;
151
152 if (acdnlun >= NUNIT) {
153 printf("wcd: too many units\n");
154 return 0;
155 }
156 if (!atapi_request_immediate) {
157 printf("wcd: configuration error, ATAPI code not present!\n");
158 return 0;
159 }
160 if ((cdp = acd_init_lun(ata, unit, ap, acdnlun, NULL)) == NULL) {
161 printf("wcd: out of memory\n");
162 return 0;
163 }
164 acdtab[acdnlun] = cdp;
165
166 if (debug) {
167 cdp->flags |= F_DEBUG;
168 atapi_dump(cdp->ata->ctrlr, cdp->lun, "info", ap, sizeof(*ap));
169 }
170
171 /* Get drive capabilities, some drives needs this repeated */
172 for (count = 0 ; count < 5 ; count++) {
173 result = atapi_request_immediate(ata, unit,
174 ATAPI_MODE_SENSE,
175 0, ATAPI_CDROM_CAP_PAGE,
176 0, 0, 0, 0,
177 sizeof(cdp->cap)>>8, sizeof(cdp->cap),
178 0, 0, 0, 0, 0, 0, 0,
179 (char *)&cdp->cap, sizeof(cdp->cap));
180 if (result.code == 0 || result.code == RES_UNDERRUN)
181 break;
182 }
183
184 /* Some drives have shorter capabilities page. */
185 if (result.code == RES_UNDERRUN)
186 result.code = 0;
187
188 if (result.code == 0) {
189 cdp->cap.max_speed = ntohs(cdp->cap.max_speed);
190 cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels);
191 cdp->cap.buf_size = ntohs(cdp->cap.buf_size);
192 cdp->cap.cur_speed = ntohs(cdp->cap.cur_speed);
193 acd_describe(cdp);
194 if (cdp->flags & F_DEBUG)
195 atapi_dump(cdp->ata->ctrlr, cdp->lun, "cap", &cdp->cap,
196 sizeof(cdp->cap));
197 }
198 /* If this is a changer device, allocate the neeeded lun's */
199 if (cdp->cap.mech == MST_MECH_CHANGER) {
200 char string[16];
201 struct acd *tmpcdp = cdp;
202
203 chp = malloc(sizeof(struct changer), M_TEMP, M_NOWAIT);
204 if (chp == NULL) {
205 printf("wcd: out of memory\n");
206 return 0;
207 }
208 bzero(chp, sizeof(struct changer));
209 result = atapi_request_immediate(ata, unit, ATAPI_MECH_STATUS,
210 0, 0, 0, 0, 0, 0, 0,
211 sizeof(struct changer)>>8,
212 sizeof(struct changer),
213 0, 0, 0, 0, 0, 0,
214 (char *)chp, sizeof(struct changer));
215 if (cdp->flags & F_DEBUG) {
216 printf("result.code=%d curr=%02x slots=%d len=%d\n",
217 result.code, chp->current_slot, chp->slots,
218 htons(chp->table_length));
219 }
220 if (result.code == RES_UNDERRUN)
221 result.code = 0;
222
223 if (result.code == 0) {
224 chp->table_length = htons(chp->table_length);
225 for (i = 0; i < chp->slots && acdnlun < NUNIT; i++) {
226 if (i > 0) {
227 tmpcdp = acd_init_lun(ata, unit, ap, acdnlun,
228 cdp->device_stats);
229 if (!tmpcdp) {
230 printf("wcd: out of memory\n");
231 return 0;
232 }
233 }
234 tmpcdp->slot = i;
235 tmpcdp->changer_info = chp;
236 printf("wcd%d: changer slot %d %s\n", acdnlun, i,
237 (chp->slot[i].present ? "disk present" : "no disk"));
238 acdtab[acdnlun++] = tmpcdp;
239 }
240 if (acdnlun >= NUNIT) {
241 printf("wcd: too many units\n");
242 return 0;
243 }
244 }
245 sprintf(string, "wcd%d-", cdp->lun);
246 devstat_add_entry(cdp->device_stats, string, tmpcdp->lun, DEV_BSIZE,
247 DEVSTAT_NO_ORDERED_TAGS,
248 DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
249 DEVSTAT_PRIORITY_CD);
250 }
251 else {
252 acdnlun++;
253 devstat_add_entry(cdp->device_stats, "wcd", cdp->lun, DEV_BSIZE,
254 DEVSTAT_NO_ORDERED_TAGS,
255 DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
256 DEVSTAT_PRIORITY_CD);
257 }
258 return 1;
259 }
260
261 void
262 acd_describe(struct acd *cdp)
263 {
264 int comma;
265 char *mechanism;
266
267 printf("wcd%d: drive speed ", cdp->lun);
268 if (cdp->cap.cur_speed != cdp->cap.max_speed)
269 printf("%d - ", cdp->cap.cur_speed * 1000 / 1024);
270 printf("%dKB/sec", cdp->cap.max_speed * 1000 / 1024);
271 if (cdp->cap.buf_size)
272 printf(", %dKB cache\n", cdp->cap.buf_size);
273
274 printf("wcd%d: supported read types:", cdp->lun);
275 comma = 0;
276 if (cdp->cap.read_cdr) {
277 printf(" CD-R"); comma = 1;
278 }
279 if (cdp->cap.read_cdrw) {
280 printf("%s CD-RW", comma ? "," : ""); comma = 1;
281 }
282 if (cdp->cap.cd_da) {
283 printf("%s CD-DA", comma ? "," : ""); comma = 1;
284 }
285 if (cdp->cap.method2)
286 printf("%s packet track", comma ? "," : "");
287 if (cdp->cap.write_cdr || cdp->cap.write_cdrw) {
288 printf("\nwcd%d: supported write types:", cdp->lun);
289 comma = 0;
290 if (cdp->cap.write_cdr) {
291 printf(" CD-R" ); comma = 1;
292 }
293 if (cdp->cap.write_cdrw) {
294 printf("%s CD-RW", comma ? "," : ""); comma = 1;
295 }
296 if (cdp->cap.test_write) {
297 printf("%s test write", comma ? "," : ""); comma = 1;
298 }
299 }
300 if (cdp->cap.audio_play) {
301 printf("\nwcd%d: Audio: ", cdp->lun);
302 if (cdp->cap.audio_play)
303 printf("play");
304 if (cdp->cap.max_vol_levels)
305 printf(", %d volume levels", cdp->cap.max_vol_levels);
306 }
307 printf("\nwcd%d: Mechanism: ", cdp->lun);
308 switch (cdp->cap.mech) {
309 case MST_MECH_CADDY:
310 mechanism = "caddy"; break;
311 case MST_MECH_TRAY:
312 mechanism = "tray"; break;
313 case MST_MECH_POPUP:
314 mechanism = "popup"; break;
315 case MST_MECH_CHANGER:
316 mechanism = "changer"; break;
317 case MST_MECH_CARTRIDGE:
318 mechanism = "cartridge"; break;
319 default:
320 mechanism = 0; break;
321 }
322 if (mechanism)
323 printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism);
324 else if (cdp->cap.eject)
325 printf("ejectable");
326
327 if (cdp->cap.mech != MST_MECH_CHANGER) {
328 printf("\nwcd%d: Medium: ", cdp->lun);
329 switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
330 case MST_CDROM:
331 printf("CD-ROM "); break;
332 case MST_CDR:
333 printf("CD-R "); break;
334 case MST_CDRW:
335 printf("CD-RW "); break;
336 case MST_DOOR_OPEN:
337 printf("door open"); break;
338 case MST_NO_DISC:
339 printf("no/blank disc inside"); break;
340 case MST_FMT_ERROR:
341 printf("medium format error"); break;
342 }
343 if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH) < MST_TYPE_MASK_HIGH) {
344 switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) {
345 case MST_DATA_120:
346 printf("120mm data disc loaded"); break;
347 case MST_AUDIO_120:
348 printf("120mm audio disc loaded"); break;
349 case MST_COMB_120:
350 printf("120mm data/audio disc loaded"); break;
351 case MST_PHOTO_120:
352 printf("120mm photo disc loaded"); break;
353 case MST_DATA_80:
354 printf("80mm data disc loaded"); break;
355 case MST_AUDIO_80:
356 printf("80mm audio disc loaded"); break;
357 case MST_COMB_80:
358 printf("80mm data/audio disc loaded"); break;
359 case MST_PHOTO_80:
360 printf("80mm photo disc loaded"); break;
361 case MST_FMT_NONE:
362 switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
363 case MST_CDROM:
364 printf("unknown medium"); break;
365 case MST_CDR:
366 case MST_CDRW:
367 printf("blank medium"); break;
368 }
369 break;
370 default:
371 printf("unknown type=0x%x", cdp->cap.medium_type); break;
372 }
373 }
374 }
375 if (cdp->cap.lock)
376 printf(cdp->cap.locked ? ", locked" : ", unlocked");
377 if (cdp->cap.prevent)
378 printf(", lock protected");
379 printf("\n");
380 }
381
382 static int
383 acdopen(dev_t dev, int flags, int fmt, struct proc *p)
384 {
385 int lun = dkunit(dev);
386 struct acd *cdp;
387
388 if (lun >= acdnlun || !atapi_request_immediate)
389 return ENXIO;
390 cdp = acdtab[lun];
391
392 if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
393 /* Prevent user eject */
394 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
395 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
396 cdp->flags |= F_LOCKED;
397 }
398 if (fmt == S_IFBLK)
399 cdp->flags |= F_BOPEN;
400 else
401 ++cdp->refcnt;
402 dev->si_bsize_phys = cdp->block_size;
403 if (!(flags & O_NONBLOCK) && acd_read_toc(cdp) && !(flags & FWRITE))
404 printf("acd%d: read_toc failed\n", lun);
405 return 0;
406 }
407
408 int
409 acdclose(dev_t dev, int flags, int fmt, struct proc *p)
410 {
411 struct acd *cdp = acdtab[dkunit(dev)];
412
413 if (fmt == S_IFBLK)
414 cdp->flags &= ~F_BOPEN;
415 else
416 --cdp->refcnt;
417
418 /* Are we the last open ?? */
419 if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
420 /* Yup, do we need to close any written tracks */
421 if ((flags & FWRITE) != 0) {
422 if ((cdp->flags & F_TRACK_PREPED) != 0) {
423 acd_close_track(cdp);
424 cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP);
425 }
426 }
427 /* Allow the user eject */
428 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
430 }
431 cdp->flags &= ~F_LOCKED;
432 return 0;
433 }
434
435 void
436 acdstrategy(struct buf *bp)
437 {
438 int lun = dkunit(bp->b_dev);
439 struct acd *cdp = acdtab[lun];
440 int x;
441
442 #ifdef NOTYET
443 /* allow write only on CD-R/RW media */ /* all for now SOS */
444 if (!(bp->b_flags & B_READ) && !(writeable_media)) {
445 bp->b_error = EROFS;
446 bp->b_flags |= B_ERROR;
447 biodone(bp);
448 return;
449 }
450 #endif
451
452 if (bp->b_bcount == 0) {
453 bp->b_resid = 0;
454 biodone(bp);
455 return;
456 }
457
458 bp->b_pblkno = bp->b_blkno;
459 bp->b_resid = bp->b_bcount;
460
461 x = splbio();
462 bufqdisksort(&cdp->buf_queue, bp);
463 acd_start(cdp);
464 splx(x);
465 }
466
467 static void
468 acd_start(struct acd *cdp)
469 {
470 struct buf *bp = bufq_first(&cdp->buf_queue);
471 u_long lba, blocks;
472 int cmd;
473 int count;
474
475 if (!bp)
476 return;
477
478 bufq_remove(&cdp->buf_queue, bp);
479
480 /* Should reject all queued entries if media have changed. */
481 if (cdp->flags & F_MEDIA_CHANGED) {
482 bp->b_error = EIO;
483 bp->b_flags |= B_ERROR;
484 biodone(bp);
485 return;
486 }
487
488 acd_select_slot(cdp);
489
490 if ((bp->b_flags & B_READ) == B_WRITE) {
491 if ((cdp->flags & F_TRACK_PREPED) == 0) {
492 if ((cdp->flags & F_TRACK_PREP) == 0) {
493 printf("wcd%d: sequence error\n", cdp->lun);
494 bp->b_error = EIO;
495 bp->b_flags |= B_ERROR;
496 biodone(bp);
497 return;
498 } else {
499 if (acd_open_track(cdp, &cdp->preptrack) != 0) {
500 biodone(bp);
501 return;
502 }
503 cdp->flags |= F_TRACK_PREPED;
504 }
505 }
506 }
507
508 if (bp->b_flags & B_READ)
509 #ifdef NOTYET
510 lba = bp->b_offset / cdp->block_size;
511 #else
512 lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE);
513 #endif
514 else
515 lba = cdp->next_writeable_lba + (bp->b_offset / cdp->block_size);
516 blocks = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size;
517
518 if ((bp->b_flags & B_READ) == B_WRITE) {
519 cmd = ATAPI_WRITE_BIG;
520 count = -bp->b_bcount;
521 } else {
522 cmd = ATAPI_READ_BIG;
523 count = bp->b_bcount;
524 }
525
526 devstat_start_transaction(cdp->device_stats);
527
528 atapi_request_callback(cdp->ata, cdp->unit, cmd, 0,
529 lba>>24, lba>>16, lba>>8, lba, 0,
530 blocks>>8, blocks, 0, 0, 0, 0, 0, 0, 0,
531 (u_char *)bp->b_data, count,
532 (atapi_callback_t *)acd_done, cdp, bp);
533 }
534
535 static void
536 acd_done(struct acd *cdp, struct buf *bp, int resid, struct atapires result)
537 {
538
539 if (result.code) {
540 atapi_error(cdp->ata, cdp->unit, result);
541 bp->b_error = EIO;
542 bp->b_flags |= B_ERROR;
543 } else {
544 bp->b_resid = resid;
545 if ((bp->b_flags & B_READ) == B_WRITE)
546 cdp->flags |= F_WRITTEN;
547 }
548 devstat_end_transaction_buf(cdp->device_stats, bp);
549 biodone(bp);
550 acd_start(cdp);
551 }
552
553 static int
554 acd_request_wait(struct acd *cdp, u_char cmd, u_char a1, u_char a2,
555 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
556 u_char a9, char *addr, int count)
557 {
558 struct atapires result;
559
560 result = atapi_request_wait(cdp->ata, cdp->unit, cmd, a1, a2, a3, a4, a5,
561 a6, a7, a8, a9, 0, 0, 0, 0, 0, 0, addr, count);
562 if (result.code) {
563 atapi_error(cdp->ata, cdp->unit, result);
564 return EIO;
565 }
566 return 0;
567 }
568
569 static __inline void
570 lba2msf(int lba, u_char *m, u_char *s, u_char *f)
571 {
572 lba += 150;
573 lba &= 0xffffff;
574 *m = lba / (60 * 75);
575 lba %= (60 * 75);
576 *s = lba / 75;
577 *f = lba % 75;
578 }
579
580 static __inline int
581 msf2lba(u_char m, u_char s, u_char f)
582 {
583 return (m * 60 + s) * 75 + f - 150;
584 }
585
586 int
587 acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
588 {
589 int lun = dkunit(dev);
590 struct acd *cdp = acdtab[lun];
591 int error = 0;
592
593 if (cdp->flags & F_MEDIA_CHANGED)
594 switch (cmd) {
595 case CDIOCRESET:
596 break;
597 default:
598 acd_read_toc(cdp);
599 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
600 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
601 cdp->flags |= F_LOCKED;
602 break;
603 }
604 switch (cmd) {
605 /*
606 case CDIOCRESUME:
607 bzero(cdb);
608 cdb->cmd = ATAPI_PAUSE;
609 cdb->b8 = 0x01;
610 return atapi_cmd_wait(cdp->ata, cdp->unit, cdb, 0, 0, timout, 0);
611 */
612 case CDIOCRESUME:
613 return acd_request_wait(cdp, ATAPI_PAUSE,
614 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0);
615
616 case CDIOCPAUSE:
617 return acd_request_wait(cdp, ATAPI_PAUSE,
618 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
619
620 case CDIOCSTART:
621 return acd_request_wait(cdp, ATAPI_START_STOP,
622 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
623
624 case CDIOCSTOP:
625 return acd_request_wait(cdp, ATAPI_START_STOP,
626 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
627
628 case CDIOCALLOW:
629 acd_select_slot(cdp);
630 cdp->flags &= ~F_LOCKED;
631 return acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
633
634 case CDIOCPREVENT:
635 acd_select_slot(cdp);
636 cdp->flags |= F_LOCKED;
637 return acd_request_wait(cdp, ATAPI_PREVENT_ALLOW,
638 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
639
640 case CDIOCRESET:
641 error = suser(p);
642 if (error)
643 return (error);
644 return acd_request_wait(cdp, ATAPI_TEST_UNIT_READY,
645 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
646
647 case CDIOCEJECT:
648 if ((cdp->flags & F_BOPEN) && cdp->refcnt)
649 return EBUSY;
650 return acd_eject(cdp, 0);
651
652 case CDIOCCLOSE:
653 if ((cdp->flags & F_BOPEN) && cdp->refcnt)
654 return 0;
655 return acd_eject(cdp, 1);
656
657 case CDIOREADTOCHEADER:
658 if (!cdp->toc.hdr.ending_track)
659 return EIO;
660 bcopy(&cdp->toc.hdr, addr, sizeof(cdp->toc.hdr));
661 break;
662
663 case CDIOREADTOCENTRYS:
664 {
665 struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr;
666 struct toc *toc = &cdp->toc;
667 struct toc buf;
668 u_long len;
669 u_char starting_track = te->starting_track;
670
671 if (!cdp->toc.hdr.ending_track)
672 return EIO;
673
674 if (te->data_len < sizeof(toc->tab[0]) ||
675 (te->data_len % sizeof(toc->tab[0])) != 0 ||
676 (te->address_format != CD_MSF_FORMAT &&
677 te->address_format != CD_LBA_FORMAT))
678 return EINVAL;
679
680 if (!starting_track)
681 starting_track = toc->hdr.starting_track;
682 else if (starting_track == 170)
683 starting_track = toc->hdr.ending_track + 1;
684 else if (starting_track < toc->hdr.starting_track ||
685 starting_track > toc->hdr.ending_track + 1)
686 return EINVAL;
687
688 len = ((toc->hdr.ending_track + 1 - starting_track) + 1) *
689 sizeof(toc->tab[0]);
690 if (te->data_len < len)
691 len = te->data_len;
692 if (len > sizeof(toc->tab))
693 return EINVAL;
694
695 if (te->address_format == CD_MSF_FORMAT) {
696 struct cd_toc_entry *entry;
697
698 buf = cdp->toc;
699 toc = &buf;
700 entry = toc->tab + (toc->hdr.ending_track + 1 -
701 toc->hdr.starting_track) + 1;
702 while (--entry >= toc->tab)
703 lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
704 &entry->addr.msf.second, &entry->addr.msf.frame);
705 }
706 return copyout(toc->tab + starting_track - toc->hdr.starting_track,
707 te->data, len);
708 }
709
710 case CDIOREADTOCENTRY:
711 {
712 struct ioc_read_toc_single_entry *te =
713 (struct ioc_read_toc_single_entry *)addr;
714 struct toc *toc = &cdp->toc;
715 struct toc buf;
716 u_char track = te->track;
717
718 if (!cdp->toc.hdr.ending_track)
719 return EIO;
720
721 if (te->address_format != CD_MSF_FORMAT &&
722 te->address_format != CD_LBA_FORMAT)
723 return EINVAL;
724
725 if (!track)
726 track = toc->hdr.starting_track;
727 else if (track == 170)
728 track = toc->hdr.ending_track + 1;
729 else if (track < toc->hdr.starting_track ||
730 track > toc->hdr.ending_track + 1)
731 return EINVAL;
732
733 if (te->address_format == CD_MSF_FORMAT) {
734 struct cd_toc_entry *entry;
735
736 buf = cdp->toc;
737 toc = &buf;
738 entry = toc->tab + (track - toc->hdr.starting_track);
739 lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute,
740 &entry->addr.msf.second, &entry->addr.msf.frame);
741 }
742 bcopy(toc->tab + track - toc->hdr.starting_track,
743 &te->entry, sizeof(struct cd_toc_entry));
744 }
745 break;
746
747 case CDIOCREADSUBCHANNEL:
748 {
749 struct ioc_read_subchannel *args =
750 (struct ioc_read_subchannel *)addr;
751 struct cd_sub_channel_info data;
752 u_long len = args->data_len;
753 int abslba, rellba;
754
755 if (len > sizeof(data) ||
756 len < sizeof(struct cd_sub_channel_header))
757 return EINVAL;
758
759 if (acd_request_wait(cdp, ATAPI_READ_SUBCHANNEL,
760 0, 0x40, 1, 0, 0, 0,
761 sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
762 0,
763 (char *)&cdp->subchan,
764 sizeof(cdp->subchan)) != 0)
765 return EIO;
766 if (cdp->flags & F_DEBUG)
767 atapi_dump(cdp->ata->ctrlr, cdp->lun, "subchan", &cdp->subchan,
768 sizeof(cdp->subchan));
769
770 abslba = cdp->subchan.abslba;
771 rellba = cdp->subchan.rellba;
772 if (args->address_format == CD_MSF_FORMAT) {
773 lba2msf(ntohl(abslba),
774 &data.what.position.absaddr.msf.minute,
775 &data.what.position.absaddr.msf.second,
776 &data.what.position.absaddr.msf.frame);
777 lba2msf(ntohl(rellba),
778 &data.what.position.reladdr.msf.minute,
779 &data.what.position.reladdr.msf.second,
780 &data.what.position.reladdr.msf.frame);
781 } else {
782 data.what.position.absaddr.lba = abslba;
783 data.what.position.reladdr.lba = rellba;
784 }
785 data.header.audio_status = cdp->subchan.audio_status;
786 data.what.position.control = cdp->subchan.control & 0xf;
787 data.what.position.addr_type = cdp->subchan.control >> 4;
788 data.what.position.track_number = cdp->subchan.track;
789 data.what.position.index_number = cdp->subchan.indx;
790 return copyout(&data, args->data, len);
791 }
792
793 case CDIOCPLAYMSF:
794 {
795 struct ioc_play_msf *args = (struct ioc_play_msf *)addr;
796
797 return acd_request_wait(cdp, ATAPI_PLAY_MSF, 0, 0,
798 args->start_m, args->start_s, args->start_f,
799 args->end_m, args->end_s, args->end_f,
800 0, 0, 0);
801 }
802
803 case CDIOCPLAYBLOCKS:
804 {
805 struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr;
806
807 return acd_request_wait(cdp, ATAPI_PLAY_BIG, 0,
808 args->blk>>24 & 0xff, args->blk>>16 & 0xff,
809 args->blk>>8 & 0xff, args->blk & 0xff,
810 args->len>>24 & 0xff, args->len>>16 & 0xff,
811 args->len>>8 & 0xff, args->len & 0xff,
812 0, 0);
813 }
814
815 case CDIOCPLAYTRACKS:
816 {
817 struct ioc_play_track *args = (struct ioc_play_track *)addr;
818 u_long start, len;
819 int t1, t2;
820
821 if (!cdp->toc.hdr.ending_track)
822 return EIO;
823
824 if (args->end_track < cdp->toc.hdr.ending_track + 1)
825 ++args->end_track;
826 if (args->end_track > cdp->toc.hdr.ending_track + 1)
827 args->end_track = cdp->toc.hdr.ending_track + 1;
828 t1 = args->start_track - cdp->toc.hdr.starting_track;
829 t2 = args->end_track - cdp->toc.hdr.starting_track;
830 if (t1 < 0 || t2 < 0)
831 return EINVAL;
832 start = ntohl(cdp->toc.tab[t1].addr.lba);
833 len = ntohl(cdp->toc.tab[t2].addr.lba) - start;
834
835 return acd_request_wait(cdp, ATAPI_PLAY_BIG, 0,
836 start>>24 & 0xff, start>>16 & 0xff,
837 start>>8 & 0xff, start & 0xff,
838 len>>24 & 0xff, len>>16 & 0xff,
839 len>>8 & 0xff, len & 0xff, 0, 0);
840 }
841
842 case CDIOCREADAUDIO:
843 {
844 struct ioc_read_audio* args = (struct ioc_read_audio*) addr;
845 int lba, frames, result = 0;
846 u_char *buffer, *ubuf = args->buffer;
847
848 if (!cdp->toc.hdr.ending_track)
849 return EIO;
850
851 if ((frames = args->nframes) < 0)
852 return EINVAL;
853
854 if (args->address_format == CD_LBA_FORMAT)
855 lba = args->address.lba;
856 else if (args->address_format == CD_MSF_FORMAT)
857 lba = msf2lba(args->address.msf.minute,
858 args->address.msf.second,
859 args->address.msf.frame);
860 else
861 return EINVAL;
862 #ifndef CD_BUFFER_BLOCKS
863 #define CD_BUFFER_BLOCKS 8
864 #endif
865 if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_TEMP, M_NOWAIT)))
866 return ENOMEM;
867
868 while (frames > 0) {
869 u_char blocks;
870 int size;
871
872 blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames;
873 size = blocks * 2352;
874
875 result = acd_request_wait(cdp, ATAPI_READ_CD, 4,
876 lba>>24, (lba>>16)&0xff,
877 (lba>>8)&0xff, lba&0xff, 0, 0,
878 blocks, 0xf0, buffer, size);
879 if (result != 0)
880 break;
881
882 result = copyout(buffer, ubuf, size);
883 if (result != 0)
884 break;
885
886 ubuf += size;
887 frames -= blocks;
888 lba += blocks;
889 }
890
891 free(buffer, M_TEMP);
892 return result;
893 }
894
895 case CDIOCGETVOL:
896 {
897 struct ioc_vol *arg = (struct ioc_vol *)addr;
898
899 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
900 0, 0, 0, 0,
901 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
902 (char *)&cdp->au, sizeof(cdp->au));
903 if (error)
904 return error;
905 if (cdp->flags & F_DEBUG)
906 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au,
907 sizeof(cdp->au));
908 if (cdp->au.page_code != CDROM_AUDIO_PAGE)
909 return EIO;
910 arg->vol[0] = cdp->au.port[0].volume;
911 arg->vol[1] = cdp->au.port[1].volume;
912 arg->vol[2] = cdp->au.port[2].volume;
913 arg->vol[3] = cdp->au.port[3].volume;
914 }
915 break;
916
917 case CDIOCSETVOL:
918 {
919 struct ioc_vol *arg = (struct ioc_vol *)addr;
920
921 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
922 0, 0, 0, 0,
923 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
924 (char *)&cdp->au, sizeof(cdp->au));
925 if (error)
926 return error;
927 if (cdp->flags & F_DEBUG)
928 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au,
929 sizeof(cdp->au));
930 if (cdp->au.page_code != CDROM_AUDIO_PAGE)
931 return EIO;
932
933 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0,
934 CDROM_AUDIO_PAGE_MASK, 0, 0, 0, 0,
935 sizeof(cdp->aumask)>>8,sizeof(cdp->aumask),
936 0,
937 (char *)&cdp->aumask, sizeof(cdp->aumask));
938 if (error)
939 return error;
940 if (cdp->flags & F_DEBUG)
941 atapi_dump(cdp->ata->ctrlr, cdp->lun, "mask", &cdp->aumask,
942 sizeof(cdp->aumask));
943
944 cdp->au.data_length = 0;
945 cdp->au.port[0].channels = CHANNEL_0;
946 cdp->au.port[1].channels = CHANNEL_1;
947 cdp->au.port[0].volume = arg->vol[0] & cdp->aumask.port[0].volume;
948 cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume;
949 cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume;
950 cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume;
951 return acd_request_wait(cdp, ATAPI_MODE_SELECT, 0x10,
952 0, 0, 0, 0, 0,
953 sizeof(cdp->au)>>8, sizeof(cdp->au),
954 0, (char *)&cdp->au, -sizeof(cdp->au));
955 }
956
957 case CDIOCSETPATCH:
958 {
959 struct ioc_patch *arg = (struct ioc_patch *)addr;
960
961 return acd_setchan(cdp, arg->patch[0], arg->patch[1],
962 arg->patch[2], arg->patch[3]);
963 }
964
965 case CDIOCSETMONO:
966 return acd_setchan(cdp, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0, 0);
967
968 case CDIOCSETSTEREO:
969 return acd_setchan(cdp, CHANNEL_0, CHANNEL_1, 0, 0);
970
971 case CDIOCSETMUTE:
972 return acd_setchan(cdp, 0, 0, 0, 0);
973
974 case CDIOCSETLEFT:
975 return acd_setchan(cdp, CHANNEL_0, CHANNEL_0, 0, 0);
976
977 case CDIOCSETRIGHT:
978 return acd_setchan(cdp, CHANNEL_1, CHANNEL_1, 0, 0);
979
980 case CDRIOCNEXTWRITEABLEADDR:
981 {
982 struct acd_track_info track_info;
983
984 if ((error = acd_read_track_info(cdp, 0xff, &track_info)))
985 break;
986 if (!track_info.nwa_valid)
987 return EINVAL;
988 cdp->next_writeable_lba = track_info.next_writeable_addr;
989 *(int*)addr = track_info.next_writeable_addr;
990 }
991 break;
992
993 case WORMIOCPREPDISK:
994 {
995 struct wormio_prepare_disk *w = (struct wormio_prepare_disk *)addr;
996
997 if (w->dummy != 0 && w->dummy != 1)
998 error = EINVAL;
999 else {
1000 error = acd_open_disk(cdp, w->dummy);
1001 if (error == 0) {
1002 cdp->flags |= F_DISK_PREPED;
1003 cdp->dummy = w->dummy;
1004 cdp->speed = w->speed;
1005 }
1006 }
1007 }
1008 break;
1009
1010 case WORMIOCPREPTRACK:
1011 {
1012 struct wormio_prepare_track *w =(struct wormio_prepare_track *)addr;
1013
1014 if (w->audio != 0 && w->audio != 1)
1015 error = EINVAL;
1016 else if (w->audio == 0 && w->preemp)
1017 error = EINVAL;
1018 else if ((cdp->flags & F_DISK_PREPED) == 0) {
1019 error = EINVAL;
1020 printf("wcd%d: sequence error (PREP_TRACK)\n", cdp->lun);
1021 } else {
1022 cdp->flags |= F_TRACK_PREP;
1023 cdp->preptrack = *w;
1024 }
1025 }
1026 break;
1027
1028 case WORMIOCFINISHTRACK:
1029 if ((cdp->flags & F_TRACK_PREPED) != 0)
1030 error = acd_close_track(cdp);
1031 cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP);
1032 break;
1033
1034 case WORMIOCFIXATION:
1035 {
1036 struct wormio_fixation *w =
1037 (struct wormio_fixation *)addr;
1038
1039 if ((cdp->flags & F_WRITTEN) == 0)
1040 error = EINVAL;
1041 else if (w->toc_type < 0 /* WORM_TOC_TYPE_AUDIO */ ||
1042 w->toc_type > 4 /* WORM_TOC_TYPE_CDI */ )
1043 error = EINVAL;
1044 else if (w->onp != 0 && w->onp != 1)
1045 error = EINVAL;
1046 else {
1047 /* no fixation needed if dummy write */
1048 if (cdp->dummy == 0)
1049 error = acd_close_disk(cdp);
1050 cdp->flags &=
1051 ~(F_WRITTEN|F_DISK_PREPED|F_TRACK_PREP|F_TRACK_PREPED);
1052 }
1053 }
1054 break;
1055
1056 case CDRIOCBLANK:
1057 return acd_blank_disk(cdp);
1058
1059 default:
1060 return ENOTTY;
1061 }
1062 return error;
1063 }
1064
1065 static int
1066 acd_read_toc(struct acd *cdp)
1067 {
1068 int ntracks, len;
1069 struct atapires result;
1070
1071 bzero(&cdp->toc, sizeof(cdp->toc));
1072 bzero(&cdp->info, sizeof(cdp->info));
1073
1074 acd_select_slot(cdp);
1075
1076 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_TEST_UNIT_READY,
1077 0, 0, 0, 0, 0, 0, 0, 0,
1078 0, 0, 0, 0, 0, 0, 0, 0, 0);
1079
1080 if (result.code == RES_ERR &&
1081 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) {
1082 cdp->flags |= F_MEDIA_CHANGED;
1083 cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
1084 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_TEST_UNIT_READY,
1085 0, 0, 0, 0, 0, 0, 0, 0,
1086 0, 0, 0, 0, 0, 0, 0, 0, 0);
1087 }
1088
1089 if (result.code) {
1090 atapi_error(cdp->ata, cdp->unit, result);
1091 return EIO;
1092 }
1093
1094 cdp->flags &= ~F_MEDIA_CHANGED;
1095
1096 len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry);
1097 if (acd_request_wait(cdp, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
1098 len>>8, len & 0xff, 0, (char *)&cdp->toc, len) != 0) {
1099 bzero(&cdp->toc, sizeof(cdp->toc));
1100 return 0;
1101 }
1102 ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1;
1103 if (ntracks <= 0 || ntracks > MAXTRK) {
1104 bzero(&cdp->toc, sizeof(cdp->toc));
1105 return 0;
1106 }
1107
1108 len = sizeof(struct ioc_toc_header) + ntracks * sizeof(struct cd_toc_entry);
1109 if (acd_request_wait(cdp, ATAPI_READ_TOC, 0, 0, 0, 0, 0, 0,
1110 len>>8, len & 0xff, 0, (char *)&cdp->toc, len) & 0xff){
1111 bzero(&cdp->toc, sizeof(cdp->toc));
1112 return 0;
1113 }
1114
1115 cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len);
1116
1117 if (acd_request_wait(cdp, ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1118 (char *)&cdp->info, sizeof(cdp->info)) != 0)
1119 bzero(&cdp->info, sizeof(cdp->info));
1120
1121 cdp->toc.tab[ntracks].control = cdp->toc.tab[ntracks - 1].control;
1122 cdp->toc.tab[ntracks].addr_type = cdp->toc.tab[ntracks - 1].addr_type;
1123 cdp->toc.tab[ntracks].track = 170;
1124 cdp->toc.tab[ntracks].addr.lba = cdp->info.volsize;
1125
1126 cdp->info.volsize = ntohl(cdp->info.volsize);
1127 cdp->info.blksize = ntohl(cdp->info.blksize);
1128
1129 if (cdp->info.volsize && cdp->toc.hdr.ending_track
1130 && (cdp->flags & F_DEBUG)) {
1131 printf("wcd%d: ", cdp->lun);
1132 if (cdp->toc.tab[0].control & 4)
1133 printf("%ldMB ", cdp->info.volsize / 512);
1134 else
1135 printf("%ld:%ld audio ", cdp->info.volsize / 75 / 60,
1136 cdp->info.volsize / 75 % 60);
1137 printf("(%ld sectors (%ld bytes)), %d tracks\n",
1138 cdp->info.volsize, cdp->info.blksize,
1139 cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1);
1140 }
1141 return 0;
1142 }
1143
1144 /*
1145 * Set up the audio channel masks.
1146 */
1147 static int
1148 acd_setchan(struct acd *cdp, u_char c0, u_char c1, u_char c2, u_char c3)
1149 {
1150 int error;
1151
1152 error = acd_request_wait(cdp, ATAPI_MODE_SENSE, 0, CDROM_AUDIO_PAGE,
1153 0, 0, 0, 0,
1154 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
1155 (char *)&cdp->au, sizeof(cdp->au));
1156 if (error)
1157 return error;
1158 if (cdp->flags & F_DEBUG)
1159 atapi_dump(cdp->ata->ctrlr, cdp->lun, "au", &cdp->au, sizeof(cdp->au));
1160 if (cdp->au.page_code != CDROM_AUDIO_PAGE)
1161 return EIO;
1162
1163 cdp->au.data_length = 0;
1164 cdp->au.port[0].channels = c0;
1165 cdp->au.port[1].channels = c1;
1166 cdp->au.port[2].channels = c2;
1167 cdp->au.port[3].channels = c3;
1168 return acd_request_wait(cdp, ATAPI_MODE_SELECT, 0x10,
1169 0, 0, 0, 0, 0,
1170 sizeof(cdp->au)>>8, sizeof(cdp->au), 0,
1171 (char *)&cdp->au, -sizeof(cdp->au));
1172 }
1173
1174 static int
1175 acd_eject(struct acd *cdp, int close)
1176 {
1177 struct atapires result;
1178
1179 acd_select_slot(cdp);
1180
1181 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_START_STOP, 1,
1182 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1183
1184 if (result.code == RES_ERR &&
1185 ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
1186 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
1187 int err;
1188
1189 if (!close)
1190 return 0;
1191 err = acd_request_wait(cdp, ATAPI_START_STOP, 0, 0, 0, 3,
1192 0, 0, 0, 0, 0, 0, 0);
1193 if (err)
1194 return err;
1195
1196 acd_read_toc(cdp);
1197
1198 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 1,
1199 0, 0, 0, 0, 0, 0, 0);
1200 cdp->flags |= F_LOCKED;
1201 return 0;
1202 }
1203 if (result.code) {
1204 atapi_error(cdp->ata, cdp->unit, result);
1205 return EIO;
1206 }
1207 if (close)
1208 return 0;
1209
1210 tsleep((caddr_t) &lbolt, PRIBIO, "wcdej1", 0);
1211 tsleep((caddr_t) &lbolt, PRIBIO, "wcdej2", 0);
1212
1213 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1214 cdp->flags &= ~F_LOCKED;
1215
1216 cdp->flags |= F_MEDIA_CHANGED;
1217 cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
1218 return acd_request_wait(cdp, ATAPI_START_STOP, 0, 0, 0, 2,
1219 0, 0, 0, 0, 0, 0, 0);
1220 }
1221
1222 static void
1223 acd_select_slot(struct acd *cdp)
1224 {
1225 if (cdp->slot < 0 || cdp->changer_info->current_slot == cdp->slot)
1226 return;
1227
1228 /* Unlock (might not be needed but its cheaper than asking) */
1229 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1230
1231 /* Unload the current media from player */
1232 acd_request_wait(cdp, ATAPI_LOAD_UNLOAD, 0, 0, 0, 2,
1233 0, 0, 0, cdp->changer_info->current_slot, 0, 0, 0);
1234
1235 /* load the wanted slot */
1236 acd_request_wait(cdp, ATAPI_LOAD_UNLOAD, 0, 0, 0, 3,
1237 0, 0, 0, cdp->slot, 0, 0, 0);
1238
1239 cdp->changer_info->current_slot = cdp->slot;
1240
1241 /* Lock the media if needed */
1242 if (cdp->flags & F_LOCKED) {
1243 acd_request_wait(cdp, ATAPI_PREVENT_ALLOW, 0, 0, 0, 1,
1244 0, 0, 0, 0, 0, 0, 0);
1245 }
1246 }
1247
1248 static int
1249 acd_open_disk(struct acd *cdp, int test)
1250 {
1251 cdp->next_writeable_lba = 0;
1252 return 0;
1253 }
1254
1255 static int
1256 acd_close_disk(struct acd *cdp)
1257 {
1258 return acd_request_wait(cdp, ATAPI_CLOSE_TRACK, 0x00,
1259 0x02, 0, 0, 0/*track*/, 0, 0, 0, 0, 0, 0);
1260 }
1261
1262 static int
1263 acd_open_track(struct acd *cdp, struct wormio_prepare_track *ptp)
1264 {
1265 struct write_param param;
1266 struct atapires result;
1267
1268 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_MODE_SENSE,
1269 0, 0x05, 0, 0, 0, 0,
1270 sizeof(param)>>8, sizeof(param),
1271 0, 0, 0, 0, 0, 0, 0,
1272 (char *)¶m, sizeof(param));
1273
1274 if (cdp->flags & F_DEBUG)
1275 atapi_dump(cdp->ata->ctrlr, cdp->lun, "0x05", ¶m, sizeof(param));
1276
1277 if (result.code == RES_UNDERRUN)
1278 result.code = 0;
1279
1280 if (result.code) {
1281 atapi_error(cdp->ata, cdp->unit, result);
1282 return EIO;
1283 }
1284 param.page_code = 0x05;
1285 param.page_length = 0x32;
1286 param.test_write = cdp->dummy ? 1 : 0;
1287 param.write_type = CDR_WTYPE_TRACK;
1288
1289 switch (ptp->audio) {
1290 /* switch (data_type) { */
1291
1292 case 0:
1293 /* case CDR_DATA: */
1294 cdp->block_size = 2048;
1295 param.track_mode = CDR_TMODE_DATA;
1296 param.data_block_type = CDR_DB_ROM_MODE1;
1297 param.session_format = CDR_SESS_CDROM;
1298 break;
1299
1300 default:
1301 /* case CDR_AUDIO: */
1302 cdp->block_size = 2352;
1303 if (ptp->preemp)
1304 param.track_mode = CDR_TMODE_AUDIO;
1305 else
1306 param.track_mode = 0;
1307 param.data_block_type = CDR_DB_RAW;
1308 param.session_format = CDR_SESS_CDROM;
1309 break;
1310
1311 /*
1312 case CDR_MODE2:
1313 param.track_mode = CDR_TMODE_DATA;
1314 param.data_block_type = CDR_DB_ROM_MODE2;
1315 param.session_format = CDR_SESS_CDROM;
1316 break;
1317
1318 case CDR_XA1:
1319 param.track_mode = CDR_TMODE_DATA;
1320 param.data_block_type = CDR_DB_XA_MODE1;
1321 param.session_format = CDR_SESS_CDROM_XA;
1322 break;
1323
1324 case CDR_XA2:
1325 param.track_mode = CDR_TMODE_DATA;
1326 param.data_block_type = CDR_DB_XA_MODE2_F1;
1327 param.session_format = CDR_SESS_CDROM_XA;
1328 break;
1329
1330 case CDR_CDI:
1331 param.track_mode = CDR_TMODE_DATA;
1332 param.data_block_type = CDR_DB_XA_MODE2_F1;
1333 param.session_format = CDR_SESS_CDI;
1334 break;
1335 */
1336 }
1337
1338 param.multi_session = CDR_MSES_NONE;
1339 param.fp = 0;
1340 param.packet_size = 0;
1341
1342 if (cdp->flags & F_DEBUG)
1343 atapi_dump(cdp->ata->ctrlr, cdp->lun, "0x05", ¶m, sizeof(param));
1344
1345 result = atapi_request_wait(cdp->ata, cdp->unit, ATAPI_MODE_SELECT,
1346 0x10, 0, 0, 0, 0, 0,
1347 sizeof(param)>>8, sizeof(param),
1348 0, 0, 0, 0, 0, 0, 0,
1349 (char *)¶m, -sizeof(param));
1350
1351 if (result.code == RES_UNDERRUN)
1352 result.code = 0;
1353
1354 if (result.code) {
1355 atapi_error(cdp->ata, cdp->unit, result);
1356 return EIO;
1357 }
1358 return 0;
1359 }
1360
1361 static int
1362 acd_close_track(struct acd *cdp)
1363 {
1364 return acd_request_wait(cdp, ATAPI_SYNCHRONIZE_CACHE, 0,
1365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1366 }
1367
1368 static int
1369 acd_read_track_info(struct acd *cdp, int lba, struct acd_track_info *info)
1370 {
1371 int error;
1372
1373 error = acd_request_wait(cdp, ATAPI_READ_TRACK_INFO, 0x01,
1374 lba>>24, (lba>>16)&0xff,
1375 (lba>>8)&0xff, lba&0xff,
1376 0,
1377 sizeof(*info)>>8, sizeof(*info), 0,
1378 (char *)info, sizeof(*info));
1379 if (error)
1380 return error;
1381 info->track_start_addr = ntohl(info->track_start_addr);
1382 info->next_writeable_addr = ntohl(info->next_writeable_addr);
1383 info->free_blocks = ntohl(info->free_blocks);
1384 info->fixed_packet_size = ntohl(info->fixed_packet_size);
1385 info->track_length = ntohl(info->track_length);
1386 return 0;
1387 }
1388
1389 static int
1390 acd_blank_disk(struct acd *cdp)
1391 {
1392 int error;
1393
1394 error = acd_request_wait(cdp, 0xa1, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1395 cdp->flags |= F_MEDIA_CHANGED;
1396 cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED);
1397 return error;
1398 }
1399
1400 static void
1401 atapi_error(struct atapi *ata, int unit, struct atapires result)
1402 {
1403 if (result.code != RES_ERR) {
1404 printf("atapi%d:%d: ERROR %d, status=%b, error=%b\n",
1405 ata->ctrlr, unit, result.code, result.status,
1406 ARS_BITS, result.error, AER_BITS);
1407 return;
1408 }
1409 switch (result.error & AER_SKEY) {
1410 case AER_SK_NOT_READY:
1411 if (ata->debug)
1412 printf("atapi%d:%d: not ready\n", ata->ctrlr, unit);
1413 break;
1414
1415 case AER_SK_BLANK_CHECK:
1416 if (ata->debug)
1417 printf("atapi%d:%d: blank check\n", ata->ctrlr, unit);
1418 break;
1419
1420 case AER_SK_MEDIUM_ERROR:
1421 if (ata->debug)
1422 printf("atapi%d:%d: medium error\n", ata->ctrlr, unit);
1423 break;
1424
1425 case AER_SK_HARDWARE_ERROR:
1426 if (ata->debug)
1427 printf("atapi%d:%d: hardware error\n", ata->ctrlr, unit);
1428 break;
1429
1430 case AER_SK_ILLEGAL_REQUEST:
1431 if (ata->debug)
1432 printf("atapi%d:%d: illegal request\n", ata->ctrlr, unit);
1433 break;
1434
1435 case AER_SK_UNIT_ATTENTION:
1436 if (ata->debug)
1437 printf("atapi%d:%d: unit attention\n", ata->ctrlr, unit);
1438 break;
1439
1440 case AER_SK_DATA_PROTECT:
1441 if (ata->debug)
1442 printf("atapi%d:%d: reading protected data\n", ata->ctrlr, unit);
1443 break;
1444
1445 case AER_SK_ABORTED_COMMAND:
1446 if (ata->debug)
1447 printf("atapi%d:%d: command aborted\n", ata->ctrlr, unit);
1448 break;
1449
1450 case AER_SK_MISCOMPARE:
1451 if (ata->debug)
1452 printf("atapi%d:%d: data don't match medium\n", ata->ctrlr, unit);
1453 break;
1454
1455 default:
1456 if (ata->debug)
1457 printf("atapi%d:%d: unknown error, status=%b, error=%b\n",
1458 ata->ctrlr, unit, result.status, ARS_BITS,
1459 result.error, AER_BITS);
1460 }
1461 }
1462
1463 static void
1464 atapi_dump(int ctrlr, int lun, char *label, void *data, int len)
1465 {
1466 u_char *p = data;
1467
1468 printf ("atapi%d%d: %s %x", ctrlr, lun, label, *p++);
1469 while (--len > 0) printf ("-%x", *p++);
1470 printf ("\n");
1471 }
1472
1473 static void
1474 acd_drvinit(void *unused)
1475 {
1476 cdevsw_add(&acd_cdevsw);
1477 }
1478
1479 SYSINIT(acddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, acd_drvinit, NULL)
Cache object: fda4c1b961c4c01f87f73ba15a6e9185
|