File: | modules/scd/../../dev/scd/scd.c |
Warning: | line 596, column 7 Copies out a struct with a union element with different sizes |
1 | /*- | |||
2 | * Copyright (c) 1995 Mikael Hybsch | |||
3 | * All rights reserved. | |||
4 | * | |||
5 | * Portions of this file are copied from mcd.c | |||
6 | * which has the following copyrights: | |||
7 | * | |||
8 | * Copyright 1993 by Holger Veit (data part) | |||
9 | * Copyright 1993 by Brian Moore (audio part) | |||
10 | * Changes Copyright 1993 by Gary Clark II | |||
11 | * Changes Copyright (C) 1994 by Andrew A. Chernov | |||
12 | * | |||
13 | * Rewrote probe routine to work on newer Mitsumi drives. | |||
14 | * Additional changes (C) 1994 by Jordan K. Hubbard | |||
15 | * | |||
16 | * All rights reserved. | |||
17 | * | |||
18 | * Redistribution and use in source and binary forms, with or without | |||
19 | * modification, are permitted provided that the following conditions | |||
20 | * are met: | |||
21 | * 1. Redistributions of source code must retain the above copyright | |||
22 | * notice, this list of conditions and the following disclaimer | |||
23 | * in this position and unchanged. | |||
24 | * 2. Redistributions in binary form must reproduce the above copyright | |||
25 | * notice, this list of conditions and the following disclaimer in the | |||
26 | * documentation and/or other materials provided with the distribution. | |||
27 | * 3. The name of the author may not be used to endorse or promote products | |||
28 | * derived from this software without specific prior written permission | |||
29 | * | |||
30 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
31 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
32 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
33 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
35 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
39 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
40 | * | |||
41 | */ | |||
42 | ||||
43 | #include <sys/cdefs.h> | |||
44 | __FBSDID("$FreeBSD: releng/11.0/sys/dev/scd/scd.c 298646 2016-04-26 15:03:15Z pfg $")__asm__(".ident\t\"" "$FreeBSD: releng/11.0/sys/dev/scd/scd.c 298646 2016-04-26 15:03:15Z pfg $" "\""); | |||
45 | ||||
46 | ||||
47 | #undef SCD_DEBUG | |||
48 | ||||
49 | #include <sys/param.h> | |||
50 | #include <sys/systm.h> | |||
51 | #include <sys/kernel.h> | |||
52 | #include <sys/conf.h> | |||
53 | #include <sys/fcntl.h> | |||
54 | #include <sys/bio.h> | |||
55 | #include <sys/cdio.h> | |||
56 | #include <sys/disk.h> | |||
57 | #include <sys/bus.h> | |||
58 | ||||
59 | #include <machine/stdarg.h> | |||
60 | ||||
61 | #include <machine/bus.h> | |||
62 | #include <machine/resource.h> | |||
63 | #include <sys/rman.h> | |||
64 | ||||
65 | #include <isa/isavar.h> | |||
66 | ||||
67 | #include <dev/scd/scdreg.h> | |||
68 | #include <dev/scd/scdvar.h> | |||
69 | ||||
70 | /* flags */ | |||
71 | #define SCDOPEN0x0001 0x0001 /* device opened */ | |||
72 | #define SCDVALID0x0002 0x0002 /* parameters loaded */ | |||
73 | #define SCDINIT0x0004 0x0004 /* device is init'd */ | |||
74 | #define SCDPROBING0x0020 0x0020 /* probing */ | |||
75 | #define SCDTOC0x0100 0x0100 /* already read toc */ | |||
76 | #define SCDMBXBSY0x0200 0x0200 /* local mbx is busy */ | |||
77 | #define SCDSPINNING0x0400 0x0400 /* drive is spun up */ | |||
78 | ||||
79 | #define SCD_S_BEGIN0 0 | |||
80 | #define SCD_S_BEGIN11 1 | |||
81 | #define SCD_S_WAITSTAT2 2 | |||
82 | #define SCD_S_WAITFIFO3 3 | |||
83 | #define SCD_S_WAITSPIN4 4 | |||
84 | #define SCD_S_WAITREAD5 5 | |||
85 | #define SCD_S_WAITPARAM6 6 | |||
86 | ||||
87 | #define RDELAY_WAIT300 300 | |||
88 | #define RDELAY_WAITREAD300 300 | |||
89 | ||||
90 | #define SCDBLKSIZE2048 2048 | |||
91 | ||||
92 | #ifdef SCD_DEBUG | |||
93 | static int scd_debuglevel = SCD_DEBUG; | |||
94 | # define XDEBUG(sc, level, fmt, args...) \ | |||
95 | do { \ | |||
96 | if (scd_debuglevel >= level) \ | |||
97 | device_printf(sc->dev, fmt, ## args); \ | |||
98 | } while (0) | |||
99 | #else | |||
100 | # define XDEBUG(sc, level, fmt, args...) | |||
101 | #endif | |||
102 | ||||
103 | #define IS_ATTENTION(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x01) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & SBIT_ATTENTION0x01) != 0) | |||
104 | #define IS_BUSY(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x80) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & SBIT_BUSY0x80) != 0) | |||
105 | #define IS_DATA_RDY(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x04) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & SBIT_DATA_READY0x04) != 0) | |||
106 | #define STATUS_BIT(sc, bit)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (bit)) != 0) ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (bit)) != 0) | |||
107 | #define FSTATUS_BIT(sc, bit)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (bit)) != 0) ((SCD_READ(sc, IREG_FSTATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (bit)) != 0) | |||
108 | ||||
109 | /* prototypes */ | |||
110 | static void hsg2msf(int hsg, bcd_t *msf); | |||
111 | static int msf2hsg(bcd_t *msf); | |||
112 | ||||
113 | static void process_attention(struct scd_softc *); | |||
114 | static int waitfor_status_bits(struct scd_softc *, int bits_set, int bits_clear); | |||
115 | static int send_cmd(struct scd_softc *, u_char cmd, u_int nargs, ...); | |||
116 | static void init_drive(struct scd_softc *); | |||
117 | static int spin_up(struct scd_softc *); | |||
118 | static int read_toc(struct scd_softc *); | |||
119 | static int get_result(struct scd_softc *, int result_len, u_char *result); | |||
120 | static void print_error(struct scd_softc *, int errcode); | |||
121 | ||||
122 | static void scd_start(struct scd_softc *); | |||
123 | static void scd_timeout(void *); | |||
124 | static void scd_doread(struct scd_softc *, int state, struct scd_mbx *mbxin); | |||
125 | ||||
126 | static int scd_eject(struct scd_softc *); | |||
127 | static int scd_stop(struct scd_softc *); | |||
128 | static int scd_pause(struct scd_softc *); | |||
129 | static int scd_resume(struct scd_softc *); | |||
130 | static int scd_playtracks(struct scd_softc *, struct ioc_play_track *pt); | |||
131 | static int scd_playmsf(struct scd_softc *, struct ioc_play_msf *msf); | |||
132 | static int scd_play(struct scd_softc *, struct ioc_play_msf *msf); | |||
133 | static int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch, int nocopyout); | |||
134 | static int read_subcode(struct scd_softc *, struct sony_subchannel_position_data *sch); | |||
135 | ||||
136 | /* for xcdplayer */ | |||
137 | static int scd_toc_header(struct scd_softc *, struct ioc_toc_header *th); | |||
138 | static int scd_toc_entrys(struct scd_softc *, struct ioc_read_toc_entry *te); | |||
139 | static int scd_toc_entry(struct scd_softc *, struct ioc_read_toc_single_entry *te); | |||
140 | #define SCD_LASTPLUS1170 170 /* don't ask, xcdplayer passes this in */ | |||
141 | ||||
142 | static d_open_t scdopen; | |||
143 | static d_close_t scdclose; | |||
144 | static d_ioctl_t scdioctl; | |||
145 | static d_strategy_t scdstrategy; | |||
146 | ||||
147 | ||||
148 | static struct cdevsw scd_cdevsw = { | |||
149 | .d_version = D_VERSION0x17122009, | |||
150 | .d_open = scdopen, | |||
151 | .d_close = scdclose, | |||
152 | .d_read = physreadphysio, | |||
153 | .d_ioctl = scdioctl, | |||
154 | .d_strategy = scdstrategy, | |||
155 | .d_name = "scd", | |||
156 | .d_flags = D_DISK0x0002, | |||
157 | }; | |||
158 | ||||
159 | int | |||
160 | scd_attach(struct scd_softc *sc) | |||
161 | { | |||
162 | int unit; | |||
163 | ||||
164 | unit = device_get_unit(sc->dev); | |||
165 | ||||
166 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (166) ); | |||
167 | init_drive(sc); | |||
168 | ||||
169 | sc->data.flags = SCDINIT0x0004; | |||
170 | sc->data.audio_status = CD_AS_AUDIO_INVALID0x00; | |||
171 | bioq_init(&sc->data.head); | |||
172 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (172 )); | |||
173 | ||||
174 | sc->scd_dev_t = make_dev(&scd_cdevsw, 8 * unit, | |||
175 | UID_ROOT0, GID_OPERATOR5, 0640, "scd%d", unit); | |||
176 | sc->scd_dev_t->si_drv1 = (void *)sc; | |||
177 | ||||
178 | return (0); | |||
179 | } | |||
180 | ||||
181 | static int | |||
182 | scdopen(struct cdev *dev, int flags, int fmt, struct thread *td) | |||
183 | { | |||
184 | struct scd_softc *sc; | |||
185 | int rc; | |||
186 | ||||
187 | sc = (struct scd_softc *)dev->si_drv1; | |||
188 | ||||
189 | /* mark all open part's invalid */ | |||
190 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (190) ); | |||
191 | if (sc->data.openflag) { | |||
192 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (192 )); | |||
193 | return (ENXIO6); | |||
194 | } | |||
195 | ||||
196 | XDEBUG(sc, 1, "DEBUG: status = 0x%x\n", SCD_READ(sc, IREG_STATUS)); | |||
197 | ||||
198 | if ((rc = spin_up(sc)) != 0) { | |||
199 | print_error(sc, rc); | |||
200 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (200 )); | |||
201 | return (EIO5); | |||
202 | } | |||
203 | if (!(sc->data.flags & SCDTOC0x0100)) { | |||
204 | int loop_count = 3; | |||
205 | ||||
206 | while (loop_count-- > 0 && (rc = read_toc(sc)) != 0) { | |||
207 | if (rc == ERR_NOT_SPINNING0x22) { | |||
208 | rc = spin_up(sc); | |||
209 | if (rc) { | |||
210 | print_error(sc, rc); | |||
211 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (211 )); | |||
212 | return (EIO5); | |||
213 | } | |||
214 | continue; | |||
215 | } | |||
216 | device_printf(sc->dev, "TOC read error 0x%x\n", rc); | |||
217 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (217 )); | |||
218 | return (EIO5); | |||
219 | } | |||
220 | } | |||
221 | ||||
222 | sc->data.openflag = 1; | |||
223 | sc->data.flags |= SCDVALID0x0002; | |||
224 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (224 )); | |||
225 | ||||
226 | return (0); | |||
227 | } | |||
228 | ||||
229 | static int | |||
230 | scdclose(struct cdev *dev, int flags, int fmt, struct thread *td) | |||
231 | { | |||
232 | struct scd_softc *sc; | |||
233 | ||||
234 | sc = (struct scd_softc *)dev->si_drv1; | |||
235 | ||||
236 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (236) ); | |||
237 | KASSERT(sc->data.openflag, ("device not open"))do { } while (0); | |||
238 | ||||
239 | if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS0x11) { | |||
240 | (void)send_cmd(sc, CMD_SPIN_DOWN0x52, 0); | |||
241 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
242 | } | |||
243 | ||||
244 | /* close channel */ | |||
245 | sc->data.openflag = 0; | |||
246 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (246 )); | |||
247 | ||||
248 | return (0); | |||
249 | } | |||
250 | ||||
251 | static void | |||
252 | scdstrategy(struct bio *bp) | |||
253 | { | |||
254 | struct scd_softc *sc; | |||
255 | ||||
256 | sc = (struct scd_softc *)bp->bio_dev->si_drv1; | |||
257 | ||||
258 | /* if device invalidated (e.g. media change, door open), error */ | |||
259 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (259) ); | |||
260 | if (!(sc->data.flags & SCDVALID0x0002)) { | |||
261 | device_printf(sc->dev, "media changed\n"); | |||
262 | bp->bio_error = EIO5; | |||
263 | goto bad; | |||
264 | } | |||
265 | ||||
266 | /* read only */ | |||
267 | if (!(bp->bio_cmd == BIO_READ0x01)) { | |||
268 | bp->bio_error = EROFS30; | |||
269 | goto bad; | |||
270 | } | |||
271 | ||||
272 | /* no data to read */ | |||
273 | if (bp->bio_bcount == 0) | |||
274 | goto done; | |||
275 | ||||
276 | if (!(sc->data.flags & SCDTOC0x0100)) { | |||
277 | bp->bio_error = EIO5; | |||
278 | goto bad; | |||
279 | } | |||
280 | ||||
281 | bp->bio_resid = 0; | |||
282 | ||||
283 | /* queue it */ | |||
284 | bioq_disksort(&sc->data.head, bp); | |||
285 | ||||
286 | /* now check whether we can perform processing */ | |||
287 | scd_start(sc); | |||
288 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (288 )); | |||
289 | return; | |||
290 | ||||
291 | bad: | |||
292 | bp->bio_flags |= BIO_ERROR0x01; | |||
293 | done: | |||
294 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (294 )); | |||
295 | bp->bio_resid = bp->bio_bcount; | |||
296 | biodone(bp); | |||
297 | return; | |||
298 | } | |||
299 | ||||
300 | static void | |||
301 | scd_start(struct scd_softc *sc) | |||
302 | { | |||
303 | struct bio *bp; | |||
304 | ||||
305 | SCD_ASSERT_LOCKED(sc)(void)0; | |||
306 | if (sc->data.flags & SCDMBXBSY0x0200) | |||
307 | return; | |||
308 | ||||
309 | bp = bioq_takefirst(&sc->data.head); | |||
310 | if (bp != 0) { | |||
311 | /* block found to process, dequeue */ | |||
312 | sc->data.flags |= SCDMBXBSY0x0200; | |||
313 | } else { | |||
314 | /* nothing to do */ | |||
315 | return; | |||
316 | } | |||
317 | ||||
318 | sc->data.mbx.retry = 3; | |||
319 | sc->data.mbx.bp = bp; | |||
320 | ||||
321 | scd_doread(sc, SCD_S_BEGIN0, &(sc->data.mbx)); | |||
322 | return; | |||
323 | } | |||
324 | ||||
325 | static int | |||
326 | scdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) | |||
327 | { | |||
328 | struct scd_softc *sc; | |||
329 | int error; | |||
330 | ||||
331 | sc = (struct scd_softc *)dev->si_drv1; | |||
332 | ||||
333 | XDEBUG(sc, 1, "ioctl: cmd=0x%lx\n", cmd); | |||
334 | ||||
335 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (335) ); | |||
336 | if (!(sc->data.flags & SCDVALID0x0002)) { | |||
| ||||
337 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (337 )); | |||
338 | return (EIO5); | |||
339 | } | |||
340 | ||||
341 | error = 0; | |||
342 | switch (cmd) { | |||
343 | case DIOCGMEDIASIZE((unsigned long) ((0x40000000) | (((sizeof(off_t)) & ((1 << 13) - 1)) << 16) | ((('d')) << 8) | ((129)))): | |||
344 | *(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize; | |||
345 | break; | |||
346 | case DIOCGSECTORSIZE((unsigned long) ((0x40000000) | (((sizeof(u_int)) & ((1 << 13) - 1)) << 16) | ((('d')) << 8) | ((128)))): | |||
347 | *(u_int *)addr = sc->data.blksize; | |||
348 | break; | |||
349 | case CDIOCPLAYTRACKS((unsigned long) ((0x80000000) | (((sizeof(struct ioc_play_track )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((1)))): | |||
350 | error = scd_playtracks(sc, (struct ioc_play_track *) addr); | |||
351 | break; | |||
352 | case CDIOCPLAYBLOCKS((unsigned long) ((0x80000000) | (((sizeof(struct ioc_play_blocks )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((2)))): | |||
353 | error = EINVAL22; | |||
354 | break; | |||
355 | case CDIOCPLAYMSF((unsigned long) ((0x80000000) | (((sizeof(struct ioc_play_msf )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((25)))): | |||
356 | error = scd_playmsf(sc, (struct ioc_play_msf *) addr); | |||
357 | break; | |||
358 | case CDIOCREADSUBCHANNEL_SYSSPACE((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_subchannel)) & ((1 << 13) - 1)) << 16 ) | ((('c')) << 8) | ((31)))): | |||
359 | return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 1); | |||
360 | case CDIOCREADSUBCHANNEL((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_subchannel)) & ((1 << 13) - 1)) << 16 ) | ((('c')) << 8) | ((3)))): | |||
361 | return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 0); | |||
362 | case CDIOREADTOCHEADER((unsigned long) ((0x40000000) | (((sizeof(struct ioc_toc_header )) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((4)))): | |||
363 | error = scd_toc_header (sc, (struct ioc_toc_header *) addr); | |||
364 | break; | |||
365 | case CDIOREADTOCENTRYS((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_toc_entry)) & ((1 << 13) - 1)) << 16 ) | ((('c')) << 8) | ((5)))): | |||
366 | return scd_toc_entrys (sc, (struct ioc_read_toc_entry*) addr); | |||
367 | case CDIOREADTOCENTRY((unsigned long) (((0x80000000|0x40000000)) | (((sizeof(struct ioc_read_toc_single_entry)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((6)))): | |||
368 | error = scd_toc_entry (sc, (struct ioc_read_toc_single_entry*) addr); | |||
369 | break; | |||
370 | case CDIOCSETPATCH((unsigned long) ((0x80000000) | (((sizeof(struct ioc_patch)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((9)))): | |||
371 | case CDIOCGETVOL((unsigned long) ((0x40000000) | (((sizeof(struct ioc_vol)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((10)))): | |||
372 | case CDIOCSETVOL((unsigned long) ((0x80000000) | (((sizeof(struct ioc_vol)) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((11)))): | |||
373 | case CDIOCSETMONO((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((12)))): | |||
374 | case CDIOCSETSTERIO((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((13)))): | |||
375 | case CDIOCSETMUTE((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((14)))): | |||
376 | case CDIOCSETLEFT((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((15)))): | |||
377 | case CDIOCSETRIGHT((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((16)))): | |||
378 | error = EINVAL22; | |||
379 | break; | |||
380 | case CDIOCRESUME((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((20)))): | |||
381 | error = scd_resume(sc); | |||
382 | break; | |||
383 | case CDIOCPAUSE((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((19)))): | |||
384 | error = scd_pause(sc); | |||
385 | break; | |||
386 | case CDIOCSTART((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((22)))): | |||
387 | error = EINVAL22; | |||
388 | break; | |||
389 | case CDIOCSTOP((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((23)))): | |||
390 | error = scd_stop(sc); | |||
391 | break; | |||
392 | case CDIOCEJECT((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((24)))): | |||
393 | error = scd_eject(sc); | |||
394 | break; | |||
395 | case CDIOCALLOW((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((26)))): | |||
396 | break; | |||
397 | case CDIOCSETDEBUG((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((17)))): | |||
398 | #ifdef SCD_DEBUG | |||
399 | scd_debuglevel++; | |||
400 | #endif | |||
401 | break; | |||
402 | case CDIOCCLRDEBUG((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('c')) << 8) | ((18)))): | |||
403 | #ifdef SCD_DEBUG | |||
404 | scd_debuglevel = 0; | |||
405 | ||||
406 | #endif | |||
407 | break; | |||
408 | default: | |||
409 | device_printf(sc->dev, "unsupported ioctl (cmd=0x%lx)\n", cmd); | |||
410 | error = ENOTTY25; | |||
411 | break; | |||
412 | } | |||
413 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (413 )); | |||
414 | return (error); | |||
415 | } | |||
416 | ||||
417 | /*************************************************************** | |||
418 | * lower level of driver starts here | |||
419 | **************************************************************/ | |||
420 | ||||
421 | static int | |||
422 | scd_playtracks(struct scd_softc *sc, struct ioc_play_track *pt) | |||
423 | { | |||
424 | struct ioc_play_msf msf; | |||
425 | int a = pt->start_track; | |||
426 | int z = pt->end_track; | |||
427 | int rc; | |||
428 | ||||
429 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
430 | if (rc == -ERR_NOT_SPINNING0x22) { | |||
431 | if (spin_up(sc) != 0) | |||
432 | return (EIO5); | |||
433 | rc = read_toc(sc); | |||
434 | } | |||
435 | if (rc != 0) { | |||
436 | print_error(sc, rc); | |||
437 | return (EIO5); | |||
438 | } | |||
439 | } | |||
440 | ||||
441 | XDEBUG(sc, 1, "playtracks from %d:%d to %d:%d\n", | |||
442 | a, pt->start_index, z, pt->end_index); | |||
443 | ||||
444 | if ( a < sc->data.first_track | |||
445 | || a > sc->data.last_track | |||
446 | || a > z | |||
447 | || z > sc->data.last_track) | |||
448 | return (EINVAL22); | |||
449 | ||||
450 | bcopy(sc->data.toc[a].start_msf, &msf.start_m, 3); | |||
451 | hsg2msf(msf2hsg(sc->data.toc[z+1].start_msf)-1, &msf.end_m); | |||
452 | ||||
453 | return scd_play(sc, &msf); | |||
454 | } | |||
455 | ||||
456 | /* The start/end msf is expected to be in bin format */ | |||
457 | static int | |||
458 | scd_playmsf(struct scd_softc *sc, struct ioc_play_msf *msfin) | |||
459 | { | |||
460 | struct ioc_play_msf msf; | |||
461 | ||||
462 | msf.start_m = bin2bcd(msfin->start_m)(bin2bcd_data[msfin->start_m]); | |||
463 | msf.start_s = bin2bcd(msfin->start_s)(bin2bcd_data[msfin->start_s]); | |||
464 | msf.start_f = bin2bcd(msfin->start_f)(bin2bcd_data[msfin->start_f]); | |||
465 | msf.end_m = bin2bcd(msfin->end_m)(bin2bcd_data[msfin->end_m]); | |||
466 | msf.end_s = bin2bcd(msfin->end_s)(bin2bcd_data[msfin->end_s]); | |||
467 | msf.end_f = bin2bcd(msfin->end_f)(bin2bcd_data[msfin->end_f]); | |||
468 | ||||
469 | return scd_play(sc, &msf); | |||
470 | } | |||
471 | ||||
472 | /* The start/end msf is expected to be in bcd format */ | |||
473 | static int | |||
474 | scd_play(struct scd_softc *sc, struct ioc_play_msf *msf) | |||
475 | { | |||
476 | int i, rc; | |||
477 | ||||
478 | XDEBUG(sc, 1, "playing: %02x:%02x:%02x -> %02x:%02x:%02x\n", | |||
479 | msf->start_m, msf->start_s, msf->start_f, | |||
480 | msf->end_m, msf->end_s, msf->end_f); | |||
481 | ||||
482 | for (i = 0; i < 2; i++) { | |||
483 | rc = send_cmd(sc, CMD_PLAY_AUDIO0x40, 7, | |||
484 | 0x03, | |||
485 | msf->start_m, msf->start_s, msf->start_f, | |||
486 | msf->end_m, msf->end_s, msf->end_f); | |||
487 | if (rc == -ERR_NOT_SPINNING0x22) { | |||
488 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
489 | if (spin_up(sc) != 0) | |||
490 | return (EIO5); | |||
491 | } else if (rc < 0) { | |||
492 | print_error(sc, rc); | |||
493 | return (EIO5); | |||
494 | } else { | |||
495 | break; | |||
496 | } | |||
497 | } | |||
498 | sc->data.audio_status = CD_AS_PLAY_IN_PROGRESS0x11; | |||
499 | bcopy((char *)msf, (char *)&sc->data.last_play, sizeof(struct ioc_play_msf)); | |||
500 | return (0); | |||
501 | } | |||
502 | ||||
503 | static int | |||
504 | scd_stop(struct scd_softc *sc) | |||
505 | { | |||
506 | ||||
507 | (void)send_cmd(sc, CMD_STOP_AUDIO0x41, 0); | |||
508 | sc->data.audio_status = CD_AS_PLAY_COMPLETED0x13; | |||
509 | return (0); | |||
510 | } | |||
511 | ||||
512 | static int | |||
513 | scd_pause(struct scd_softc *sc) | |||
514 | { | |||
515 | struct sony_subchannel_position_data subpos; | |||
516 | ||||
517 | if (sc->data.audio_status != CD_AS_PLAY_IN_PROGRESS0x11) | |||
518 | return (EINVAL22); | |||
519 | ||||
520 | if (read_subcode(sc, &subpos) != 0) | |||
521 | return (EIO5); | |||
522 | ||||
523 | if (send_cmd(sc, CMD_STOP_AUDIO0x41, 0) != 0) | |||
524 | return (EIO5); | |||
525 | ||||
526 | sc->data.last_play.start_m = subpos.abs_msf[0]; | |||
527 | sc->data.last_play.start_s = subpos.abs_msf[1]; | |||
528 | sc->data.last_play.start_f = subpos.abs_msf[2]; | |||
529 | sc->data.audio_status = CD_AS_PLAY_PAUSED0x12; | |||
530 | ||||
531 | XDEBUG(sc, 1, "pause @ %02x:%02x:%02x\n", | |||
532 | sc->data.last_play.start_m, | |||
533 | sc->data.last_play.start_s, | |||
534 | sc->data.last_play.start_f); | |||
535 | ||||
536 | return (0); | |||
537 | } | |||
538 | ||||
539 | static int | |||
540 | scd_resume(struct scd_softc *sc) | |||
541 | { | |||
542 | ||||
543 | if (sc->data.audio_status != CD_AS_PLAY_PAUSED0x12) | |||
544 | return (EINVAL22); | |||
545 | return scd_play(sc, &sc->data.last_play); | |||
546 | } | |||
547 | ||||
548 | static int | |||
549 | scd_eject(struct scd_softc *sc) | |||
550 | { | |||
551 | ||||
552 | sc->data.audio_status = CD_AS_AUDIO_INVALID0x00; | |||
553 | sc->data.flags &= ~(SCDSPINNING0x0400|SCDTOC0x0100); | |||
554 | ||||
555 | if (send_cmd(sc, CMD_STOP_AUDIO0x41, 0) != 0 || | |||
556 | send_cmd(sc, CMD_SPIN_DOWN0x52, 0) != 0 || | |||
557 | send_cmd(sc, CMD_EJECT0x50, 0) != 0) | |||
558 | { | |||
559 | return (EIO5); | |||
560 | } | |||
561 | return (0); | |||
562 | } | |||
563 | ||||
564 | static int | |||
565 | scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout) | |||
566 | { | |||
567 | struct sony_subchannel_position_data q; | |||
568 | struct cd_sub_channel_info data; | |||
569 | ||||
570 | XDEBUG(sc, 1, "subchan af=%d, df=%d\n", | |||
571 | sch->address_format, sch->data_format); | |||
572 | ||||
573 | if (sch->address_format != CD_MSF_FORMAT2) | |||
574 | return (EINVAL22); | |||
575 | ||||
576 | if (sch->data_format != CD_CURRENT_POSITION1) | |||
577 | return (EINVAL22); | |||
578 | ||||
579 | if (read_subcode(sc, &q) != 0) | |||
580 | return (EIO5); | |||
581 | ||||
582 | data.header.audio_status = sc->data.audio_status; | |||
583 | data.what.position.data_format = CD_MSF_FORMAT2; | |||
584 | data.what.position.track_number = bcd2bin(q.track_number)(bcd2bin_data[q.track_number]); | |||
585 | data.what.position.reladdr.msf.unused = 0; | |||
586 | data.what.position.reladdr.msf.minute = bcd2bin(q.rel_msf[0])(bcd2bin_data[q.rel_msf[0]]); | |||
587 | data.what.position.reladdr.msf.second = bcd2bin(q.rel_msf[1])(bcd2bin_data[q.rel_msf[1]]); | |||
588 | data.what.position.reladdr.msf.frame = bcd2bin(q.rel_msf[2])(bcd2bin_data[q.rel_msf[2]]); | |||
589 | data.what.position.absaddr.msf.unused = 0; | |||
590 | data.what.position.absaddr.msf.minute = bcd2bin(q.abs_msf[0])(bcd2bin_data[q.abs_msf[0]]); | |||
591 | data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1])(bcd2bin_data[q.abs_msf[1]]); | |||
592 | data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2])(bcd2bin_data[q.abs_msf[2]]); | |||
593 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (593 )); | |||
594 | ||||
595 | if (nocopyout == 0) { | |||
596 | if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0) | |||
| ||||
597 | return (EFAULT14); | |||
598 | } else { | |||
599 | bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len)); | |||
600 | } | |||
601 | return (0); | |||
602 | } | |||
603 | ||||
604 | int | |||
605 | scd_probe(struct scd_softc *sc) | |||
606 | { | |||
607 | struct sony_drive_configuration drive_config; | |||
608 | int rc; | |||
609 | static char namebuf[8+16+8+3]; | |||
610 | char *s = namebuf; | |||
611 | int loop_count = 0; | |||
612 | ||||
613 | sc->data.flags = SCDPROBING0x0020; | |||
614 | ||||
615 | bzero(&drive_config, sizeof(drive_config)); | |||
616 | ||||
617 | again: | |||
618 | /* Reset drive */ | |||
619 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESET_DRIVE)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x80)); | |||
620 | ||||
621 | /* Calm down */ | |||
622 | DELAY(300000); | |||
623 | ||||
624 | /* Only the ATTENTION bit may be set */ | |||
625 | if ((SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & ~1) != 0) { | |||
626 | XDEBUG(sc, 1, "too many bits set. probe failed.\n"); | |||
627 | return (ENXIO6); | |||
628 | } | |||
629 | rc = send_cmd(sc, CMD_GET_DRIVE_CONFIG0x00, 0); | |||
630 | if (rc != sizeof(drive_config)) { | |||
631 | /* Sometimes if the drive is playing audio I get */ | |||
632 | /* the bad result 82. Fix by repeating the reset */ | |||
633 | if (rc > 0 && loop_count++ == 0) | |||
634 | goto again; | |||
635 | return (ENXIO6); | |||
636 | } | |||
637 | if (get_result(sc, rc, (u_char *)&drive_config) != 0) | |||
638 | return (ENXIO6); | |||
639 | ||||
640 | bcopy(drive_config.vendor, namebuf, 8); | |||
641 | s = namebuf+8; | |||
642 | while (*(s-1) == ' ') /* Strip trailing spaces */ | |||
643 | s--; | |||
644 | *s++ = ' '; | |||
645 | bcopy(drive_config.product, s, 16); | |||
646 | s += 16; | |||
647 | while (*(s-1) == ' ') | |||
648 | s--; | |||
649 | *s++ = ' '; | |||
650 | bcopy(drive_config.revision, s, 8); | |||
651 | s += 8; | |||
652 | while (*(s-1) == ' ') | |||
653 | s--; | |||
654 | *s = 0; | |||
655 | ||||
656 | sc->data.name = namebuf; | |||
657 | ||||
658 | if (drive_config.config & 0x10) | |||
659 | sc->data.double_speed = 1; | |||
660 | else | |||
661 | sc->data.double_speed = 0; | |||
662 | ||||
663 | return (0); | |||
664 | } | |||
665 | ||||
666 | static int | |||
667 | read_subcode(struct scd_softc *sc, struct sony_subchannel_position_data *scp) | |||
668 | { | |||
669 | int rc; | |||
670 | ||||
671 | rc = send_cmd(sc, CMD_GET_SUBCHANNEL_DATA0x21, 0); | |||
672 | if (rc < 0 || rc < sizeof(*scp)) | |||
673 | return (EIO5); | |||
674 | if (get_result(sc, rc, (u_char *)scp) != 0) | |||
675 | return (EIO5); | |||
676 | return (0); | |||
677 | } | |||
678 | ||||
679 | /* State machine copied from mcd.c */ | |||
680 | ||||
681 | /* This (and the code in mcd.c) will not work with more than one drive */ | |||
682 | /* because there is only one sc->ch_mbxsave below. Should fix that some day. */ | |||
683 | /* (sc->ch_mbxsave & state should probably be included in the scd_data struct and */ | |||
684 | /* the unit number used as first argument to scd_doread().) /Micke */ | |||
685 | ||||
686 | /* state machine to process read requests | |||
687 | * initialize with SCD_S_BEGIN: reset state machine | |||
688 | * SCD_S_WAITSTAT: wait for ready (!busy) | |||
689 | * SCD_S_WAITSPIN: wait for drive to spin up (if not spinning) | |||
690 | * SCD_S_WAITFIFO: wait for param fifo to get ready, them exec. command. | |||
691 | * SCD_S_WAITREAD: wait for data ready, read data | |||
692 | * SCD_S_WAITPARAM: wait for command result params, read them, error if bad data read. | |||
693 | */ | |||
694 | ||||
695 | static void | |||
696 | scd_timeout(void *arg) | |||
697 | { | |||
698 | struct scd_softc *sc; | |||
699 | sc = (struct scd_softc *)arg; | |||
700 | ||||
701 | SCD_ASSERT_LOCKED(sc)(void)0; | |||
702 | scd_doread(sc, sc->ch_state, sc->ch_mbxsave); | |||
703 | } | |||
704 | ||||
705 | static void | |||
706 | scd_doread(struct scd_softc *sc, int state, struct scd_mbx *mbxin) | |||
707 | { | |||
708 | struct scd_mbx *mbx = (state!=SCD_S_BEGIN0) ? sc->ch_mbxsave : mbxin; | |||
709 | struct bio *bp = mbx->bp; | |||
710 | int i; | |||
711 | int blknum; | |||
712 | caddr_t addr; | |||
713 | static char sdata[3]; /* Must be preserved between calls to this function */ | |||
714 | ||||
715 | SCD_ASSERT_LOCKED(sc)(void)0; | |||
716 | loop: | |||
717 | switch (state) { | |||
718 | case SCD_S_BEGIN0: | |||
719 | mbx = sc->ch_mbxsave = mbxin; | |||
720 | ||||
721 | case SCD_S_BEGIN11: | |||
722 | /* get status */ | |||
723 | mbx->count = RDELAY_WAIT300; | |||
724 | ||||
725 | process_attention(sc); | |||
726 | goto trystat; | |||
727 | ||||
728 | case SCD_S_WAITSTAT2: | |||
729 | sc->ch_state = SCD_S_WAITSTAT2; | |||
730 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
731 | if (mbx->count-- <= 0) { | |||
732 | device_printf(sc->dev, "timeout. drive busy.\n"); | |||
733 | goto harderr; | |||
734 | } | |||
735 | ||||
736 | trystat: | |||
737 | if (IS_BUSY(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x80) != 0)) { | |||
738 | sc->ch_state = SCD_S_WAITSTAT2; | |||
739 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
740 | return; | |||
741 | } | |||
742 | ||||
743 | process_attention(sc); | |||
744 | ||||
745 | /* reject, if audio active */ | |||
746 | if (sc->data.audio_status & CD_AS_PLAY_IN_PROGRESS0x11) { | |||
747 | device_printf(sc->dev, "audio is active\n"); | |||
748 | goto harderr; | |||
749 | } | |||
750 | ||||
751 | mbx->sz = sc->data.blksize; | |||
752 | ||||
753 | /* for first block */ | |||
754 | mbx->nblk = howmany(bp->bio_bcount, mbx->sz)(((bp->bio_bcount)+((mbx->sz)-1))/(mbx->sz)); | |||
755 | mbx->skip = 0; | |||
756 | ||||
757 | nextblock: | |||
758 | if (!(sc->data.flags & SCDVALID0x0002)) | |||
759 | goto changed; | |||
760 | ||||
761 | blknum = bp->bio_offset / mbx->sz + mbx->skip/mbx->sz; | |||
762 | ||||
763 | XDEBUG(sc, 2, "scd_doread: read blknum=%d\n", blknum); | |||
764 | ||||
765 | /* build parameter block */ | |||
766 | hsg2msf(blknum, sdata); | |||
767 | ||||
768 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
769 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x40)); | |||
770 | SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x04)); | |||
771 | ||||
772 | if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) | |||
773 | goto writeparam; | |||
774 | ||||
775 | mbx->count = 100; | |||
776 | sc->ch_state = SCD_S_WAITFIFO3; | |||
777 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
778 | return; | |||
779 | ||||
780 | case SCD_S_WAITSPIN4: | |||
781 | sc->ch_state = SCD_S_WAITSPIN4; | |||
782 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
783 | if (mbx->count-- <= 0) { | |||
784 | device_printf(sc->dev, "timeout waiting for drive to spin up.\n"); | |||
785 | goto harderr; | |||
786 | } | |||
787 | if (!STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) { | |||
788 | sc->ch_state = SCD_S_WAITSPIN4; | |||
789 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
790 | return; | |||
791 | } | |||
792 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
793 | switch ((i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1))) & 0xf0) { | |||
794 | case 0x20: | |||
795 | i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
796 | print_error(sc, i); | |||
797 | goto harderr; | |||
798 | case 0x00: | |||
799 | (void)SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
800 | sc->data.flags |= SCDSPINNING0x0400; | |||
801 | break; | |||
802 | } | |||
803 | XDEBUG(sc, 1, "DEBUG: spin up complete\n"); | |||
804 | ||||
805 | state = SCD_S_BEGIN11; | |||
806 | goto loop; | |||
807 | ||||
808 | case SCD_S_WAITFIFO3: | |||
809 | sc->ch_state = SCD_S_WAITFIFO3; | |||
810 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
811 | if (mbx->count-- <= 0) { | |||
812 | device_printf(sc->dev, "timeout. write param not ready.\n"); | |||
813 | goto harderr; | |||
814 | } | |||
815 | if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) { | |||
816 | sc->ch_state = SCD_S_WAITFIFO3; | |||
817 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
818 | return; | |||
819 | } | |||
820 | XDEBUG(sc, 1, "mbx->count (writeparamwait) = %d(%d)\n", mbx->count, 100); | |||
821 | ||||
822 | writeparam: | |||
823 | /* The reason this test isn't done 'till now is to make sure */ | |||
824 | /* that it is ok to send the SPIN_UP cmd below. */ | |||
825 | if (!(sc->data.flags & SCDSPINNING0x0400)) { | |||
826 | XDEBUG(sc, 1, "spinning up drive ...\n"); | |||
827 | SCD_WRITE(sc, OREG_COMMAND, CMD_SPIN_UP)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0), (0x51)); | |||
828 | mbx->count = 300; | |||
829 | sc->ch_state = SCD_S_WAITSPIN4; | |||
830 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
831 | return; | |||
832 | } | |||
833 | ||||
834 | /* send the read command */ | |||
835 | SCD_WRITE(sc, OREG_WPARAMS, sdata[0])bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (sdata[0])); | |||
836 | SCD_WRITE(sc, OREG_WPARAMS, sdata[1])bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (sdata[1])); | |||
837 | SCD_WRITE(sc, OREG_WPARAMS, sdata[2])bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (sdata[2])); | |||
838 | SCD_WRITE(sc, OREG_WPARAMS, 0)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (0)); | |||
839 | SCD_WRITE(sc, OREG_WPARAMS, 0)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (0)); | |||
840 | SCD_WRITE(sc, OREG_WPARAMS, 1)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (1)); | |||
841 | SCD_WRITE(sc, OREG_COMMAND, CMD_READ)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0), (0x34)); | |||
842 | ||||
843 | mbx->count = RDELAY_WAITREAD300; | |||
844 | for (i = 0; i < 50; i++) { | |||
845 | if (STATUS_BIT(sc, SBIT_DATA_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x04)) != 0)) | |||
846 | goto got_data; | |||
847 | DELAY(100); | |||
848 | } | |||
849 | ||||
850 | sc->ch_state = SCD_S_WAITREAD5; | |||
851 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
852 | return; | |||
853 | ||||
854 | case SCD_S_WAITREAD5: | |||
855 | sc->ch_state = SCD_S_WAITREAD5; | |||
856 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
857 | if (mbx->count-- <= 0) { | |||
858 | if (STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) | |||
859 | goto got_param; | |||
860 | device_printf(sc->dev, "timeout while reading data\n"); | |||
861 | goto readerr; | |||
862 | } | |||
863 | if (!STATUS_BIT(sc, SBIT_DATA_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x04)) != 0)) { | |||
864 | process_attention(sc); | |||
865 | if (!(sc->data.flags & SCDVALID0x0002)) | |||
866 | goto changed; | |||
867 | sc->ch_state = SCD_S_WAITREAD5; | |||
868 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
869 | return; | |||
870 | } | |||
871 | XDEBUG(sc, 2, "mbx->count (after RDY_BIT) = %d(%d)\n", mbx->count, RDELAY_WAITREAD); | |||
872 | ||||
873 | got_data: | |||
874 | /* data is ready */ | |||
875 | addr = bp->bio_data + mbx->skip; | |||
876 | SCD_WRITE(sc, OREG_CONTROL, CBIT_DATA_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x04)); | |||
877 | SCD_READ_MULTI(sc, IREG_DATA, addr, mbx->sz)bus_space_read_multi_1((sc->port)->r_bustag, (sc->port )->r_bushandle, (2), (addr), (mbx->sz)); | |||
878 | ||||
879 | mbx->count = 100; | |||
880 | for (i = 0; i < 20; i++) { | |||
881 | if (STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) | |||
882 | goto waitfor_param; | |||
883 | DELAY(100); | |||
884 | } | |||
885 | goto waitfor_param; | |||
886 | ||||
887 | case SCD_S_WAITPARAM6: | |||
888 | sc->ch_state = SCD_S_WAITPARAM6; | |||
889 | callout_stop(&sc->timer)_callout_stop_safe(&sc->timer, 0, ((void *)0)); | |||
890 | if (mbx->count-- <= 0) { | |||
891 | device_printf(sc->dev, "timeout waiting for params\n"); | |||
892 | goto readerr; | |||
893 | } | |||
894 | ||||
895 | waitfor_param: | |||
896 | if (!STATUS_BIT(sc, SBIT_RESULT_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & (0x02)) != 0)) { | |||
897 | sc->ch_state = SCD_S_WAITPARAM6; | |||
898 | callout_reset(&sc->timer, hz / 100, scd_timeout, sc)callout_reset_sbt_on(((&sc->timer)), tick_sbt * ((hz / 100)), 0, ((scd_timeout)), ((sc)), (-1), 0x0100); /* XXX */ | |||
899 | return; | |||
900 | } | |||
901 | #ifdef SCD_DEBUG | |||
902 | if (mbx->count < 100 && scd_debuglevel > 0) | |||
903 | device_printf(sc->dev, "mbx->count (paramwait) = %d(%d)\n", mbx->count, 100); | |||
904 | #endif | |||
905 | ||||
906 | got_param: | |||
907 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
908 | switch ((i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1))) & 0xf0) { | |||
909 | case 0x50: | |||
910 | switch (i) { | |||
911 | case ERR_FATAL_READ_ERROR10x53: | |||
912 | case ERR_FATAL_READ_ERROR20x57: | |||
913 | device_printf(sc->dev, "unrecoverable read error 0x%x\n", i); | |||
914 | goto harderr; | |||
915 | } | |||
916 | break; | |||
917 | case 0x20: | |||
918 | i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
919 | switch (i) { | |||
920 | case ERR_NOT_SPINNING0x22: | |||
921 | XDEBUG(sc, 1, "read error: drive not spinning\n"); | |||
922 | if (mbx->retry-- > 0) { | |||
923 | state = SCD_S_BEGIN11; | |||
924 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
925 | goto loop; | |||
926 | } | |||
927 | goto harderr; | |||
928 | default: | |||
929 | print_error(sc, i); | |||
930 | goto readerr; | |||
931 | } | |||
932 | case 0x00: | |||
933 | i = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
934 | break; | |||
935 | } | |||
936 | ||||
937 | if (--mbx->nblk > 0) { | |||
938 | mbx->skip += mbx->sz; | |||
939 | goto nextblock; | |||
940 | } | |||
941 | ||||
942 | /* return buffer */ | |||
943 | bp->bio_resid = 0; | |||
944 | biodone(bp); | |||
945 | ||||
946 | sc->data.flags &= ~SCDMBXBSY0x0200; | |||
947 | scd_start(sc); | |||
948 | return; | |||
949 | } | |||
950 | ||||
951 | readerr: | |||
952 | if (mbx->retry-- > 0) { | |||
953 | device_printf(sc->dev, "retrying ...\n"); | |||
954 | state = SCD_S_BEGIN11; | |||
955 | goto loop; | |||
956 | } | |||
957 | harderr: | |||
958 | /* invalidate the buffer */ | |||
959 | bp->bio_error = EIO5; | |||
960 | bp->bio_flags |= BIO_ERROR0x01; | |||
961 | bp->bio_resid = bp->bio_bcount; | |||
962 | biodone(bp); | |||
963 | ||||
964 | sc->data.flags &= ~SCDMBXBSY0x0200; | |||
965 | scd_start(sc); | |||
966 | return; | |||
967 | ||||
968 | changed: | |||
969 | device_printf(sc->dev, "media changed\n"); | |||
970 | goto harderr; | |||
971 | } | |||
972 | ||||
973 | static void | |||
974 | hsg2msf(int hsg, bcd_t *msf) | |||
975 | { | |||
976 | ||||
977 | hsg += 150; | |||
978 | M_msf(msf)msf[0] = bin2bcd(hsg / 4500)(bin2bcd_data[hsg / 4500]); | |||
979 | hsg %= 4500; | |||
980 | S_msf(msf)msf[1] = bin2bcd(hsg / 75)(bin2bcd_data[hsg / 75]); | |||
981 | F_msf(msf)msf[2] = bin2bcd(hsg % 75)(bin2bcd_data[hsg % 75]); | |||
982 | } | |||
983 | ||||
984 | static int | |||
985 | msf2hsg(bcd_t *msf) | |||
986 | { | |||
987 | ||||
988 | return (bcd2bin(M_msf(msf))(bcd2bin_data[msf[0]]) * 60 + | |||
989 | bcd2bin(S_msf(msf))(bcd2bin_data[msf[1]])) * 75 + | |||
990 | bcd2bin(F_msf(msf))(bcd2bin_data[msf[2]]) - 150; | |||
991 | } | |||
992 | ||||
993 | static void | |||
994 | process_attention(struct scd_softc *sc) | |||
995 | { | |||
996 | unsigned char code; | |||
997 | int count = 0; | |||
998 | ||||
999 | while (IS_ATTENTION(sc)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)) & 0x01) != 0) && count++ < 30) { | |||
1000 | SCD_WRITE(sc, OREG_CONTROL, CBIT_ATTENTION_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x01)); | |||
1001 | code = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
1002 | ||||
1003 | #ifdef SCD_DEBUG | |||
1004 | if (scd_debuglevel > 0) { | |||
1005 | if (count == 1) | |||
1006 | device_printf(sc->dev, "DEBUG: ATTENTIONS = 0x%x", code); | |||
1007 | else | |||
1008 | printf(",0x%x", code); | |||
1009 | } | |||
1010 | #endif | |||
1011 | ||||
1012 | switch (code) { | |||
1013 | case ATTEN_SPIN_DOWN0x27: | |||
1014 | sc->data.flags &= ~SCDSPINNING0x0400; | |||
1015 | break; | |||
1016 | ||||
1017 | case ATTEN_SPIN_UP_DONE0x24: | |||
1018 | sc->data.flags |= SCDSPINNING0x0400; | |||
1019 | break; | |||
1020 | ||||
1021 | case ATTEN_AUDIO_DONE0x90: | |||
1022 | sc->data.audio_status = CD_AS_PLAY_COMPLETED0x13; | |||
1023 | break; | |||
1024 | ||||
1025 | case ATTEN_DRIVE_LOADED0x80: | |||
1026 | sc->data.flags &= ~(SCDTOC0x0100|SCDSPINNING0x0400|SCDVALID0x0002); | |||
1027 | sc->data.audio_status = CD_AS_AUDIO_INVALID0x00; | |||
1028 | break; | |||
1029 | ||||
1030 | case ATTEN_EJECT_PUSHED0x81: | |||
1031 | sc->data.flags &= ~SCDVALID0x0002; | |||
1032 | break; | |||
1033 | } | |||
1034 | DELAY(100); | |||
1035 | } | |||
1036 | #ifdef SCD_DEBUG | |||
1037 | if (scd_debuglevel > 0 && count > 0) | |||
1038 | printf("\n"); | |||
1039 | #endif | |||
1040 | } | |||
1041 | ||||
1042 | /* Returns 0 OR sony error code */ | |||
1043 | static int | |||
1044 | spin_up(struct scd_softc *sc) | |||
1045 | { | |||
1046 | unsigned char res_reg[12]; | |||
1047 | unsigned int res_size; | |||
1048 | int rc; | |||
1049 | int loop_count = 0; | |||
1050 | ||||
1051 | again: | |||
1052 | rc = send_cmd(sc, CMD_SPIN_UP0x51, 0, 0, res_reg, &res_size); | |||
1053 | if (rc != 0) { | |||
1054 | XDEBUG(sc, 2, "CMD_SPIN_UP error 0x%x\n", rc); | |||
1055 | return (rc); | |||
1056 | } | |||
1057 | ||||
1058 | if (!(sc->data.flags & SCDTOC0x0100)) { | |||
1059 | rc = send_cmd(sc, CMD_READ_TOC0x30, 0); | |||
1060 | if (rc == ERR_NOT_SPINNING0x22) { | |||
1061 | if (loop_count++ < 3) | |||
1062 | goto again; | |||
1063 | return (rc); | |||
1064 | } | |||
1065 | if (rc != 0) | |||
1066 | return (rc); | |||
1067 | } | |||
1068 | ||||
1069 | sc->data.flags |= SCDSPINNING0x0400; | |||
1070 | ||||
1071 | return (0); | |||
1072 | } | |||
1073 | ||||
1074 | static struct sony_tracklist * | |||
1075 | get_tl(struct sony_toc *toc, int size) | |||
1076 | { | |||
1077 | struct sony_tracklist *tl = &toc->tracks[0]; | |||
1078 | ||||
1079 | if (tl->track != 0xb0) | |||
1080 | return (tl); | |||
1081 | if (tl->track != 0xb1) | |||
1082 | return (tl); | |||
1083 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
1084 | if (tl->track != 0xb2) | |||
1085 | return (tl); | |||
1086 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
1087 | if (tl->track != 0xb3) | |||
1088 | return (tl); | |||
1089 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
1090 | if (tl->track != 0xb4) | |||
1091 | return (tl); | |||
1092 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
1093 | if (tl->track != 0xc0) | |||
1094 | return (tl); | |||
1095 | tl = (struct sony_tracklist *)((char *)tl + 9); | |||
1096 | return (tl); | |||
1097 | } | |||
1098 | ||||
1099 | static int | |||
1100 | read_toc(struct scd_softc *sc) | |||
1101 | { | |||
1102 | struct sony_toc toc; | |||
1103 | struct sony_tracklist *tl; | |||
1104 | int rc, i, j; | |||
1105 | u_long first, last; | |||
1106 | ||||
1107 | rc = send_cmd(sc, CMD_GET_TOC0x24, 1, 1); | |||
1108 | if (rc < 0) | |||
1109 | return (rc); | |||
1110 | if (rc > sizeof(toc)) { | |||
1111 | device_printf(sc->dev, "program error: toc too large (%d)\n", rc); | |||
1112 | return (EIO5); | |||
1113 | } | |||
1114 | if (get_result(sc, rc, (u_char *)&toc) != 0) | |||
1115 | return (EIO5); | |||
1116 | ||||
1117 | XDEBUG(sc, 1, "toc read. len = %d, sizeof(toc) = %d\n", rc, sizeof(toc)); | |||
1118 | ||||
1119 | tl = get_tl(&toc, rc); | |||
1120 | first = msf2hsg(tl->start_msf); | |||
1121 | last = msf2hsg(toc.lead_out_start_msf); | |||
1122 | sc->data.blksize = SCDBLKSIZE2048; | |||
1123 | sc->data.disksize = last*sc->data.blksize/DEV_BSIZE(1<<9); | |||
1124 | ||||
1125 | XDEBUG(sc, 1, "firstsector = %ld, lastsector = %ld", first, last); | |||
1126 | ||||
1127 | sc->data.first_track = bcd2bin(toc.first_track)(bcd2bin_data[toc.first_track]); | |||
1128 | sc->data.last_track = bcd2bin(toc.last_track)(bcd2bin_data[toc.last_track]); | |||
1129 | if (sc->data.last_track > (MAX_TRACKS100-2)) | |||
1130 | sc->data.last_track = MAX_TRACKS100-2; | |||
1131 | for (j = 0, i = sc->data.first_track; i <= sc->data.last_track; i++, j++) { | |||
1132 | sc->data.toc[i].adr = tl[j].adr; | |||
1133 | sc->data.toc[i].ctl = tl[j].ctl; /* for xcdplayer */ | |||
1134 | bcopy(tl[j].start_msf, sc->data.toc[i].start_msf, 3); | |||
1135 | #ifdef SCD_DEBUG | |||
1136 | if (scd_debuglevel > 0) { | |||
1137 | if ((j % 3) == 0) { | |||
1138 | printf("\n"); | |||
1139 | device_printf(sc->dev, "tracks "); | |||
1140 | } | |||
1141 | printf("[%03d: %2d %2d %2d] ", i, | |||
1142 | bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]), | |||
1143 | bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]), | |||
1144 | bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]])); | |||
1145 | } | |||
1146 | #endif | |||
1147 | } | |||
1148 | bcopy(toc.lead_out_start_msf, sc->data.toc[sc->data.last_track+1].start_msf, 3); | |||
1149 | #ifdef SCD_DEBUG | |||
1150 | if (scd_debuglevel > 0) { | |||
1151 | i = sc->data.last_track+1; | |||
1152 | printf("[END: %2d %2d %2d]\n", | |||
1153 | bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]), | |||
1154 | bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]), | |||
1155 | bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]])); | |||
1156 | } | |||
1157 | #endif | |||
1158 | ||||
1159 | sc->data.flags |= SCDTOC0x0100; | |||
1160 | ||||
1161 | return (0); | |||
1162 | } | |||
1163 | ||||
1164 | static void | |||
1165 | init_drive(struct scd_softc *sc) | |||
1166 | { | |||
1167 | int rc; | |||
1168 | ||||
1169 | rc = send_cmd(sc, CMD_SET_DRIVE_PARAM0x10, 2, | |||
1170 | 0x05, 0x03 | ((sc->data.double_speed) ? 0x04: 0)); | |||
1171 | if (rc != 0) | |||
1172 | device_printf(sc->dev, "Unable to set parameters. Errcode = 0x%x\n", rc); | |||
1173 | } | |||
1174 | ||||
1175 | /* Returns 0 or errno */ | |||
1176 | static int | |||
1177 | get_result(struct scd_softc *sc, int result_len, u_char *result) | |||
1178 | { | |||
1179 | int loop_index = 2; /* send_cmd() reads two bytes ... */ | |||
1180 | ||||
1181 | XDEBUG(sc, 1, "DEBUG: get_result: bytes=%d\n", result_len); | |||
1182 | ||||
1183 | while (result_len-- > 0) { | |||
1184 | if (loop_index++ >= 10) { | |||
1185 | loop_index = 1; | |||
1186 | if (waitfor_status_bits(sc, SBIT_RESULT_READY0x02, 0)) | |||
1187 | return (EIO5); | |||
1188 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
1189 | } | |||
1190 | if (result) | |||
1191 | *result++ = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
1192 | else | |||
1193 | (void)SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
1194 | } | |||
1195 | return (0); | |||
1196 | } | |||
1197 | ||||
1198 | /* Returns -0x100 for timeout, -(drive error code) OR number of result bytes */ | |||
1199 | static int | |||
1200 | send_cmd(struct scd_softc *sc, u_char cmd, u_int nargs, ...) | |||
1201 | { | |||
1202 | va_list ap; | |||
1203 | u_char c; | |||
1204 | int rc; | |||
1205 | int i; | |||
1206 | ||||
1207 | if (waitfor_status_bits(sc, 0, SBIT_BUSY0x80)) { | |||
1208 | device_printf(sc->dev, "drive busy\n"); | |||
1209 | return (-0x100); | |||
1210 | } | |||
1211 | ||||
1212 | XDEBUG(sc, 1, "DEBUG: send_cmd: cmd=0x%x nargs=%d", cmd, nargs); | |||
1213 | ||||
1214 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
1215 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RPARAM_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x40)); | |||
1216 | ||||
1217 | for (i = 0; i < 100; i++) | |||
1218 | if (FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) | |||
1219 | break; | |||
1220 | if (!FSTATUS_BIT(sc, FBIT_WPARAM_READY)((bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3)) & (0x01)) != 0)) { | |||
1221 | XDEBUG(sc, 1, "\nwparam timeout\n"); | |||
1222 | return (-EIO5); | |||
1223 | } | |||
1224 | ||||
1225 | va_start(ap, nargs)__builtin_va_start((ap), (nargs)); | |||
1226 | for (i = 0; i < nargs; i++) { | |||
1227 | c = (u_char)va_arg(ap, int)__builtin_va_arg((ap), int); | |||
1228 | SCD_WRITE(sc, OREG_WPARAMS, c)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1), (c)); | |||
1229 | XDEBUG(sc, 1, ",{0x%x}", c); | |||
1230 | } | |||
1231 | va_end(ap)__builtin_va_end(ap); | |||
1232 | XDEBUG(sc, 1, "\n"); | |||
1233 | ||||
1234 | SCD_WRITE(sc, OREG_COMMAND, cmd)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0), (cmd)); | |||
1235 | ||||
1236 | rc = waitfor_status_bits(sc, SBIT_RESULT_READY0x02, SBIT_BUSY0x80); | |||
1237 | if (rc) | |||
1238 | return (-0x100); | |||
1239 | ||||
1240 | SCD_WRITE(sc, OREG_CONTROL, CBIT_RESULT_READY_CLEAR)bus_space_write_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (3), (0x02)); | |||
1241 | switch ((rc = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1))) & 0xf0) { | |||
1242 | case 0x20: | |||
1243 | rc = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
1244 | /* FALLTHROUGH */ | |||
1245 | case 0x50: | |||
1246 | XDEBUG(sc, 1, "DEBUG: send_cmd: drive_error=0x%x\n", rc); | |||
1247 | return (-rc); | |||
1248 | case 0x00: | |||
1249 | default: | |||
1250 | rc = SCD_READ(sc, IREG_RESULT)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (1)); | |||
1251 | XDEBUG(sc, 1, "DEBUG: send_cmd: result_len=%d\n", rc); | |||
1252 | return (rc); | |||
1253 | } | |||
1254 | } | |||
1255 | ||||
1256 | static void | |||
1257 | print_error(struct scd_softc *sc, int errcode) | |||
1258 | { | |||
1259 | ||||
1260 | switch (errcode) { | |||
1261 | case -ERR_CD_NOT_LOADED0x20: | |||
1262 | device_printf(sc->dev, "door is open\n"); | |||
1263 | break; | |||
1264 | case -ERR_NO_CD_INSIDE0x21: | |||
1265 | device_printf(sc->dev, "no cd inside\n"); | |||
1266 | break; | |||
1267 | default: | |||
1268 | if (errcode == -0x100 || errcode > 0) | |||
1269 | device_printf(sc->dev, "device timeout\n"); | |||
1270 | else | |||
1271 | device_printf(sc->dev, "unexpected error 0x%x\n", -errcode); | |||
1272 | break; | |||
1273 | } | |||
1274 | } | |||
1275 | ||||
1276 | /* Returns 0 or errno value */ | |||
1277 | static int | |||
1278 | waitfor_status_bits(struct scd_softc *sc, int bits_set, int bits_clear) | |||
1279 | { | |||
1280 | u_int flags = sc->data.flags; | |||
1281 | u_int max_loop; | |||
1282 | u_char c = 0; | |||
1283 | ||||
1284 | if (flags & SCDPROBING0x0020) { | |||
1285 | max_loop = 0; | |||
1286 | while (max_loop++ < 1000) { | |||
1287 | c = SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)); | |||
1288 | if (c == 0xff) | |||
1289 | return (EIO5); | |||
1290 | if (c & SBIT_ATTENTION0x01) { | |||
1291 | process_attention(sc); | |||
1292 | continue; | |||
1293 | } | |||
1294 | if ((c & bits_set) == bits_set && | |||
1295 | (c & bits_clear) == 0) | |||
1296 | { | |||
1297 | break; | |||
1298 | } | |||
1299 | DELAY(10000); | |||
1300 | } | |||
1301 | } else { | |||
1302 | max_loop = 100; | |||
1303 | while (max_loop-- > 0) { | |||
1304 | c = SCD_READ(sc, IREG_STATUS)bus_space_read_1((sc->port)->r_bustag, (sc->port)-> r_bushandle, (0)); | |||
1305 | if (c & SBIT_ATTENTION0x01) { | |||
1306 | process_attention(sc); | |||
1307 | continue; | |||
1308 | } | |||
1309 | if ((c & bits_set) == bits_set && | |||
1310 | (c & bits_clear) == 0) | |||
1311 | { | |||
1312 | break; | |||
1313 | } | |||
1314 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (1314 )); | |||
1315 | pause("waitfor", hz/10)pause_sbt(("waitfor"), tick_sbt * (hz/10), 0, 0x0100); | |||
1316 | SCD_LOCK(sc)__mtx_lock_flags(&((((&sc->mtx))))->mtx_lock, ( (0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (1316 )); | |||
1317 | } | |||
1318 | } | |||
1319 | if ((c & bits_set) == bits_set && | |||
1320 | (c & bits_clear) == 0) | |||
1321 | { | |||
1322 | return (0); | |||
1323 | } | |||
1324 | #ifdef SCD_DEBUG | |||
1325 | if (scd_debuglevel > 0) | |||
1326 | device_printf(sc->dev, "DEBUG: waitfor: TIMEOUT (0x%x,(0x%x,0x%x))\n", c, bits_set, bits_clear); | |||
1327 | else | |||
1328 | #endif | |||
1329 | device_printf(sc->dev, "timeout.\n"); | |||
1330 | return (EIO5); | |||
1331 | } | |||
1332 | ||||
1333 | /* these two routines for xcdplayer - "borrowed" from mcd.c */ | |||
1334 | static int | |||
1335 | scd_toc_header (struct scd_softc *sc, struct ioc_toc_header* th) | |||
1336 | { | |||
1337 | int rc; | |||
1338 | ||||
1339 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
1340 | print_error(sc, rc); | |||
1341 | return (EIO5); | |||
1342 | } | |||
1343 | ||||
1344 | th->starting_track = sc->data.first_track; | |||
1345 | th->ending_track = sc->data.last_track; | |||
1346 | th->len = 0; /* not used */ | |||
1347 | ||||
1348 | return (0); | |||
1349 | } | |||
1350 | ||||
1351 | static int | |||
1352 | scd_toc_entrys (struct scd_softc *sc, struct ioc_read_toc_entry *te) | |||
1353 | { | |||
1354 | struct cd_toc_entry toc_entry; | |||
1355 | int rc, i, len = te->data_len; | |||
1356 | ||||
1357 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
1358 | print_error(sc, rc); | |||
1359 | return (EIO5); | |||
1360 | } | |||
1361 | ||||
1362 | /* find the toc to copy*/ | |||
1363 | i = te->starting_track; | |||
1364 | if (i == SCD_LASTPLUS1170) | |||
1365 | i = sc->data.last_track + 1; | |||
1366 | ||||
1367 | /* verify starting track */ | |||
1368 | if (i < sc->data.first_track || i > sc->data.last_track+1) | |||
1369 | return (EINVAL22); | |||
1370 | ||||
1371 | /* valid length ? */ | |||
1372 | if (len < sizeof(struct cd_toc_entry) | |||
1373 | || (len % sizeof(struct cd_toc_entry)) != 0) | |||
1374 | return (EINVAL22); | |||
1375 | ||||
1376 | /* copy the toc data */ | |||
1377 | toc_entry.control = sc->data.toc[i].ctl; | |||
1378 | toc_entry.addr_type = te->address_format; | |||
1379 | toc_entry.track = i; | |||
1380 | if (te->address_format == CD_MSF_FORMAT2) { | |||
1381 | toc_entry.addr.msf.unused = 0; | |||
1382 | toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]); | |||
1383 | toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]); | |||
1384 | toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]]); | |||
1385 | } | |||
1386 | SCD_UNLOCK(sc)__mtx_unlock_flags(&((((&sc->mtx))))->mtx_lock, ((0)), ("/usr/src/sys/modules/scd/../../dev/scd/scd.c"), (1386 )); | |||
1387 | ||||
1388 | /* copy the data back */ | |||
1389 | if (copyout(&toc_entry, te->data, sizeof(struct cd_toc_entry)) != 0) | |||
1390 | return (EFAULT14); | |||
1391 | ||||
1392 | return (0); | |||
1393 | } | |||
1394 | ||||
1395 | ||||
1396 | static int | |||
1397 | scd_toc_entry (struct scd_softc *sc, struct ioc_read_toc_single_entry *te) | |||
1398 | { | |||
1399 | struct cd_toc_entry toc_entry; | |||
1400 | int rc, i; | |||
1401 | ||||
1402 | if (!(sc->data.flags & SCDTOC0x0100) && (rc = read_toc(sc)) != 0) { | |||
1403 | print_error(sc, rc); | |||
1404 | return (EIO5); | |||
1405 | } | |||
1406 | ||||
1407 | /* find the toc to copy*/ | |||
1408 | i = te->track; | |||
1409 | if (i == SCD_LASTPLUS1170) | |||
1410 | i = sc->data.last_track + 1; | |||
1411 | ||||
1412 | /* verify starting track */ | |||
1413 | if (i < sc->data.first_track || i > sc->data.last_track+1) | |||
1414 | return (EINVAL22); | |||
1415 | ||||
1416 | /* copy the toc data */ | |||
1417 | toc_entry.control = sc->data.toc[i].ctl; | |||
1418 | toc_entry.addr_type = te->address_format; | |||
1419 | toc_entry.track = i; | |||
1420 | if (te->address_format == CD_MSF_FORMAT2) { | |||
1421 | toc_entry.addr.msf.unused = 0; | |||
1422 | toc_entry.addr.msf.minute = bcd2bin(sc->data.toc[i].start_msf[0])(bcd2bin_data[sc->data.toc[i].start_msf[0]]); | |||
1423 | toc_entry.addr.msf.second = bcd2bin(sc->data.toc[i].start_msf[1])(bcd2bin_data[sc->data.toc[i].start_msf[1]]); | |||
1424 | toc_entry.addr.msf.frame = bcd2bin(sc->data.toc[i].start_msf[2])(bcd2bin_data[sc->data.toc[i].start_msf[2]]); | |||
1425 | } | |||
1426 | ||||
1427 | /* copy the data back */ | |||
1428 | bcopy(&toc_entry, &te->entry, sizeof(struct cd_toc_entry)); | |||
1429 | ||||
1430 | return (0); | |||
1431 | } |