1 /***************************************************************************
2 * *
3 * LIBDSK: General floppy and diskimage access library *
4 * Copyright (C) 2001-2,2007 John Elliott <seasip.webmaster@gmail.com> *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU Library General Public *
8 * License as published by the Free Software Foundation; either *
9 * version 2 of the License, or (at your option) any later version. *
10 * *
11 * This library is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * Library General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Library General Public *
17 * License along with this library; if not, write to the Free *
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
19 * MA 02111-1307, USA *
20 * *
21 ***************************************************************************/
22
23 /* This driver provides limited read-only support for Teledisk files. It is
24 * based entirely on the file format documentation at
25 * <http://www.fpns.net/willy/wteledsk.htm>. No code from wteledsk has been
26 * used in this file, since it is under GPL and LibDsk is under LGPL.
27 *
28 * (GPL code from wteledsk was incorporated into comptlzh.c / comptlzh.h;
29 * in that case, it was relicensed as LGPL with permission).
30 *
31 * Current bugs / limitations:
32 * - No write support. The Teledisk format isn't really adapted to
33 * in-place rewrites of the sort that LibDsk likes to do, but in
34 * theory it would be possible to support writing to sectors that are
35 * stored uncompressed (type 0). This would require updating sector CRCs.
36 *
37 * - No support for images split into multiple files (.TD0, .TD1, .TD2...)
38 *
39 * - No support for advanced compression. Rather than having it built-in to
40 * this driver, we use a compression module to convert advanced-compression
41 * TD0 files to normal, using code from wteledsk.
42 *
43 * There's also an "old advanced" compression, which uses 12-bit LZ
44 * compression in 6k blocks, so another 'comp' driver would be needed for
45 * that.
46 *
47 */
48
49
50 #include "drvi.h"
51 #include "drvtele.h"
52
53 extern unsigned short teledisk_crc(unsigned char *buf, unsigned short len);
54
55 DRV_CLASS dc_tele =
56 {
57 sizeof(TELE_DSK_DRIVER),
58 "tele",
59 "TeleDisk file driver",
60 tele_open,
61 NULL, /* tele_creat */
62 tele_close,
63 tele_read,
64 NULL, /* tele_write */
65 NULL, /* tele_format */
66 tele_getgeom,
67 tele_secid,
68 tele_xseek,
69 tele_status,
70 tele_xread,
71 NULL, /* tele_xwrite */
72 NULL, /* tele_tread */
73 NULL, /* tele_xtread */
74 tele_option_enum,
75 tele_option_set,
76 tele_option_get,
77 NULL, /* tele_trackids */
78 NULL /* tele_rtread */
79 };
80
81 /* #define MONITOR(x) printf x */
82
83 #define MONITOR(x)
84
85
86 #define DC_CHECK(s) \
87 TELE_DSK_DRIVER *self; \
88 if (s->dr_class != &dc_tele) return DSK_ERR_BADPTR; \
89 self = (TELE_DSK_DRIVER *)s;
90
91 /* Check that the data rate and recording mode match those used when the
92 * disk was imaged. */
check_rate(TELE_DSK_DRIVER * self,const DSK_GEOMETRY * geom)93 static dsk_err_t check_rate(TELE_DSK_DRIVER *self, const DSK_GEOMETRY *geom)
94 {
95 int fm;
96
97 switch(self->tele_head.datarate & 0x7F)
98 {
99 /* Allow SD / DD interchangeably with 250/300. */
100 case 0:
101 case 1: if (geom->dg_datarate != RATE_SD &&
102 geom->dg_datarate != RATE_DD) return DSK_ERR_NOADDR;
103 break;
104 case 2: if (geom->dg_datarate != RATE_HD) return DSK_ERR_NOADDR;
105 break;
106 }
107 fm = ((geom->dg_fm & RECMODE_MASK) == RECMODE_FM) ? 0x80 : 0;
108 if (fm != (self->tele_head.datarate & 0x80))
109 {
110 return DSK_ERR_NOADDR;
111 }
112 return DSK_ERR_OK;
113 }
114
tele_fread(TELE_DSK_DRIVER * self,tele_byte * buf,int count)115 static dsk_err_t tele_fread(TELE_DSK_DRIVER *self, tele_byte *buf, int count)
116 {
117 if (!buf)
118 {
119 if (fseek(self->tele_fp, count, SEEK_CUR))
120 {
121 return DSK_ERR_SYSERR;
122 }
123 }
124 else
125 {
126 if (fread(buf, 1, count, self->tele_fp) < (size_t)count)
127 {
128 return DSK_ERR_SYSERR;
129 }
130 }
131 return DSK_ERR_OK;
132 }
133
tele_readsechead(TELE_DSK_DRIVER * self)134 static dsk_err_t tele_readsechead(TELE_DSK_DRIVER *self)
135 {
136 dsk_err_t err;
137 tele_byte buf[6];
138
139 memset(&self->tele_sechead, 0, sizeof(self->tele_sechead));
140 err = tele_fread(self, buf, 6);
141 if (err) return err;
142 self->tele_sechead.cylinder_id = buf[0];
143 self->tele_sechead.head_id = buf[1];
144 self->tele_sechead.sector_id = buf[2];
145 self->tele_sechead.sector_len = (128 << buf[3]);
146 self->tele_sechead.syndrome = buf[4];
147 self->tele_sechead.header_crc = buf[5];
148
149 /* Syndromes 0x10 and 0x20 omit sector data */
150 if ((self->tele_sechead.syndrome & 0x30) == 0)
151 {
152 err = tele_fread(self, buf, 3);
153 if (err) return err;
154 self->tele_sechead.compressed_len = (((tele_word)buf[1]) << 8) |
155 buf[0];
156 self->tele_sechead.encoding = buf[2];
157 }
158 return DSK_ERR_OK;
159 }
160
161 /* Read the sector described by tele_sechead */
tele_readsec(TELE_DSK_DRIVER * self,unsigned char * buf)162 static dsk_err_t tele_readsec(TELE_DSK_DRIVER *self, unsigned char *buf)
163 {
164 int n, w, wleft, plen, ptype;
165 dsk_err_t err;
166 size_t len = self->tele_sechead.sector_len;
167 tele_byte pattern[257];
168
169 if (self->tele_sechead.syndrome & 0x30) /* Nothing there */
170 {
171 if (buf) memset(buf, 0xF6, len);
172 return DSK_ERR_OK;
173 }
174 switch(self->tele_sechead.encoding)
175 {
176 case 0: /* Uncompressed */
177 MONITOR(("tele_readsec @ 0x%08lx: Type 0 len %d\n",
178 ftell(self->tele_fp), len));
179 return tele_fread(self, buf, len);
180 case 1: /* One pattern */
181 MONITOR(("tele_readsec @ 0x%08lx: Type 1 len 4\n",
182 ftell(self->tele_fp)));
183 err = tele_fread(self, pattern, 4);
184 if (err) return err;
185
186 if (buf) for (n = 0; n < (int)len; n+= 2)
187 {
188 buf[n] = pattern[2];
189 buf[n+1] = pattern[3];
190 }
191 return DSK_ERR_OK;
192 case 2: /* More than one pattern */
193 w = 0;
194 MONITOR(("tele_readsec @ 0x%08lx: Type 2 \n",
195 ftell(self->tele_fp)));
196 while ((size_t)w < len)
197 {
198 wleft = len - w;
199 err = tele_fread(self, pattern, 2);
200 if (err) return err;
201 ptype = pattern[0];
202 plen = pattern[1];
203 MONITOR(("tele_readsec @ 0x%08lx: Type 2 ptype=%d plen=%d\n",
204 ftell(self->tele_fp), ptype, plen));
205 if (ptype == 0)
206 {
207 err = tele_fread(self, pattern, plen);
208 if (err) return err;
209 if (plen > wleft) plen = wleft;
210 if (buf) memcpy(buf + w, pattern, plen);
211 w += plen;
212 continue;
213 }
214 err = tele_fread(self, pattern, (1 << ptype));
215 for (n = 0; n < plen; n++)
216 {
217 if (buf)
218 {
219 /* Ensure the amount of data written does not exceed len */
220 if ((1 << ptype) > wleft)
221 memcpy(buf + w,
222 pattern,wleft);
223 else memcpy(buf + w,
224 pattern, 1 << ptype);
225 }
226 w += (1 << ptype);
227 wleft -= (1 << ptype);
228 }
229 }
230 return DSK_ERR_OK;
231 default:
232 #ifndef WIN16
233 fprintf(stderr, "Teledisk: Unsupported sector compression method %d!\n", self->tele_sechead.encoding);
234 #endif
235 break;
236 }
237 return DSK_ERR_NOTIMPL;
238 }
239
240 /* We cache previously-encountered track addresses in self->tele_track_addr
241 * to avoid doing a linear search every time a track is needed. */
tele_seektrack(TELE_DSK_DRIVER * self,dsk_pcyl_t cylinder,dsk_phead_t head)242 static dsk_err_t tele_seektrack(TELE_DSK_DRIVER *self, dsk_pcyl_t cylinder,
243 dsk_phead_t head)
244 {
245 long startpos;
246 int c, h, s;
247 dsk_err_t err;
248
249 h = head;
250 c = cylinder;
251 startpos = 0;
252 MONITOR(("tele_seektrack: cylinder=%d head=%d\n", cylinder, head));
253
254 do
255 {
256 MONITOR(("tele_seektrack: Trying c%d h%d\n", c, h));
257 if (c < 100 && h < 2 && self->tele_track_addr[c][h] != 0)
258 {
259 MONITOR(("tele_seektrack: starting at c%d h%d\n", c, h));
260 startpos = self->tele_track_addr[c][h];
261 }
262 if (h == 0)
263 {
264 h = 1;
265 --c;
266 }
267 else
268 {
269 --h;
270 }
271 }
272 while (startpos == 0 && c >= 0);
273
274 if (startpos == 0)
275 {
276 #ifndef WIN16
277 fprintf(stderr, "drv_tele internal error: Cannot find cylinder 0 head 0\n");
278 #endif
279 return DSK_ERR_CTRLR;
280 }
281
282 if (fseek(self->tele_fp, startpos, SEEK_SET))
283 return DSK_ERR_SYSERR;
284
285 do
286 {
287 tele_byte buf[4];
288 startpos = ftell(self->tele_fp);
289 err = tele_fread(self, buf, 4);
290 if (err)
291 {
292 return DSK_ERR_NOADDR;
293 }
294 self->tele_trackhead.sectors = buf[0];
295 self->tele_trackhead.cylinder = buf[1];
296 self->tele_trackhead.head = buf[2];
297 self->tele_trackhead.crc = buf[3];
298 c = self->tele_trackhead.cylinder;
299 h = self->tele_trackhead.head;
300 MONITOR(("tele_seektrack: c%d h%d at 0x%08lx\n", c, h, startpos));
301 if (c < 100 && h < 2 && self->tele_track_addr[c][h] == 0)
302 {
303 self->tele_track_addr[c][h] = startpos;
304 }
305 if ((dsk_pcyl_t)c == cylinder && (dsk_phead_t)h == head)
306 {
307 return DSK_ERR_OK;
308 }
309 for (s = 0; s < self->tele_trackhead.sectors; s++)
310 {
311 err = tele_readsechead(self);
312 if (err) return err;
313 err = tele_readsec(self, NULL);
314 if (err) return err;
315 }
316
317 }
318 while(1);
319 /* Should never happen, but need to shut Pacific C up */
320 return DSK_ERR_UNKNOWN;
321 }
322
tele_seeksec(TELE_DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t * request_len,size_t * sseclen)323 dsk_err_t tele_seeksec(TELE_DSK_DRIVER *self, const DSK_GEOMETRY *geom,
324 dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected,
325 dsk_phead_t head_expected, dsk_psect_t sector,
326 size_t *request_len, size_t *sseclen)
327 {
328 dsk_err_t err;
329 int s;
330 long pos;
331
332 MONITOR(("tele_seeksec: Searching for c=%d h=%d s=%d on c=%d h=%d\n",
333 cyl_expected, head_expected, sector,
334 cylinder, head));
335 err = tele_seektrack(self, cylinder, head);
336
337 for (s = 0; s < self->tele_trackhead.sectors; s++)
338 {
339 pos = ftell(self->tele_fp);
340 err = tele_readsechead(self);
341 if (err) return err;
342 MONITOR(("tele_seeksec: c%d h%d s%d at 0x%08lx (%d/%d)\n",
343 self->tele_sechead.cylinder_id,
344 self->tele_sechead.head_id,
345 self->tele_sechead.sector_id, pos,
346 s, self->tele_trackhead.sectors));
347 if (self->tele_sechead.sector_id == sector &&
348 self->tele_sechead.cylinder_id == cyl_expected &&
349 self->tele_sechead.head_id == head_expected)
350 {
351 *sseclen = self->tele_sechead.sector_len;
352 /* Sector shorter than expected. Report a data error, and set
353 * request_len to the actual size. */
354 if (*sseclen < *request_len)
355 {
356 *request_len = *sseclen;
357 err = DSK_ERR_DATAERR;
358 }
359 /* Sector longer than expected. Report a data error but don't change
360 * request_len */
361 else if ((*sseclen) > (*request_len))
362 {
363 err = DSK_ERR_DATAERR;
364 }
365 return err;
366 }
367 /* Skip over that sector and on to the next */
368 err = tele_readsec(self, NULL);
369 }
370 return DSK_ERR_NOADDR;
371 }
372
373
tele_open(DSK_DRIVER * s,const char * filename)374 dsk_err_t tele_open(DSK_DRIVER *s, const char *filename)
375 {
376 unsigned char header[12];
377 DC_CHECK(s);
378
379 self->tele_fp = fopen(filename, "rb");
380 if (!self->tele_fp) return DSK_ERR_NOTME;
381 /* This does use fread not tele_fread, because it's not compressed
382 * by the Advanced compression */
383 if (fread(header, 1, sizeof(header), self->tele_fp) < (int)sizeof(header) ||
384 (memcmp(header, "TD", 2) && memcmp(header, "td", 2)))
385 {
386 fclose(self->tele_fp);
387 return DSK_ERR_NOTME;
388 }
389 memcpy(self->tele_head.magic, header, 2);
390 self->tele_head.magic[2] = 0;
391 self->tele_head.volume_seq = header[2];
392 self->tele_head.volume_id = header[3];
393 self->tele_head.ver = header[4];
394 self->tele_head.datarate = header[5];
395 self->tele_head.drivetype = header[6];
396 self->tele_head.doubletrack = header[7];
397 self->tele_head.dosmode = header[8];
398 self->tele_head.sides = header[9];
399 self->tele_head.crc = ((tele_word)header[11]) << 8 | header[10];
400
401 /* Check header CRC. */
402 if (teledisk_crc(header, 10) != self->tele_head.crc)
403 {
404 fclose(self->tele_fp);
405 return DSK_ERR_NOTME;
406 }
407
408 /* Advanced compression not supported -- see separate comptele */
409 if (!strcmp((char *)header, "td"))
410 {
411 #ifndef WIN16
412 fprintf(stderr, "LibDsk TD0 driver: Advanced compression not supported\n");
413 #endif
414 fclose(self->tele_fp);
415 return DSK_ERR_NOTIMPL;
416 }
417 /* Read a comment if there is one */
418 if (self->tele_head.doubletrack & 0x80)
419 {
420 int comment_len, n;
421 if (tele_fread(self, header, 10))
422 {
423 fclose(self->tele_fp);
424 return DSK_ERR_SYSERR;
425 }
426 comment_len = ((int)(header[3])) << 8 | header[2];
427 self->tele_comment = dsk_malloc(comment_len + sizeof(TELE_COMMENT));
428 if (!self->tele_comment)
429 {
430 fclose(self->tele_fp);
431 return DSK_ERR_NOMEM;
432 }
433 self->tele_comment->year = header[4] + 1900;
434 self->tele_comment->mon = header[5];
435 self->tele_comment->day = header[6];
436 self->tele_comment->hour = header[7];
437 self->tele_comment->min = header[8];
438 self->tele_comment->sec = header[9];
439 if (tele_fread(self, (tele_byte *)self->tele_comment->text, comment_len))
440 {
441 fclose(self->tele_fp);
442 return DSK_ERR_SYSERR;
443 }
444 self->tele_comment->text[comment_len] = 0;
445 for (n = 0; n < comment_len; n++)
446 {
447 if (self->tele_comment->text[n] == 0 &&
448 self->tele_comment->text[n+1] == 0)
449 {
450 self->tele_comment->text[n] = '\r';
451 self->tele_comment->text[n+1] = '\n';
452 }
453 }
454 dsk_set_comment(s, self->tele_comment->text);
455 }
456 self->tele_track_addr[0][0] = ftell(self->tele_fp);
457
458 return DSK_ERR_OK;
459 }
460
tele_creat(DSK_DRIVER * self,const char * filename)461 dsk_err_t tele_creat(DSK_DRIVER *self, const char *filename)
462 {
463 return DSK_ERR_RDONLY;
464 }
tele_close(DSK_DRIVER * s)465 dsk_err_t tele_close(DSK_DRIVER *s)
466 {
467 DC_CHECK(s);
468
469 if (fclose(self->tele_fp)) return DSK_ERR_SYSERR;
470 if (self->tele_comment)
471 {
472 dsk_free(self->tele_comment);
473 self->tele_comment = NULL;
474 }
475 return DSK_ERR_OK;
476 }
477
478
479
tele_write(DSK_DRIVER * self,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)480 dsk_err_t tele_write(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
481 const void *buf, dsk_pcyl_t cylinder,
482 dsk_phead_t head, dsk_psect_t sector)
483 {
484 return DSK_ERR_RDONLY;
485 }
tele_format(DSK_DRIVER * self,DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,const DSK_FORMAT * format,unsigned char filler)486 dsk_err_t tele_format(DSK_DRIVER *self, DSK_GEOMETRY *geom,
487 dsk_pcyl_t cylinder, dsk_phead_t head,
488 const DSK_FORMAT *format, unsigned char filler)
489 {
490 return DSK_ERR_RDONLY;
491 }
tele_secid(DSK_DRIVER * s,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,DSK_FORMAT * result)492 dsk_err_t tele_secid(DSK_DRIVER *s, const DSK_GEOMETRY *geom,
493 dsk_pcyl_t cylinder, dsk_phead_t head,
494 DSK_FORMAT *result)
495 {
496 unsigned int n, m;
497 dsk_err_t err;
498
499 DC_CHECK(s);
500
501 /* Single-sided? */
502 if (head > 0 && self->tele_head.sides < 2)
503 {
504 return DSK_ERR_NOADDR;
505 }
506 err = check_rate(self, geom); if (err) return err;
507 err = tele_seektrack(self, cylinder, head);
508 if (err) return err;
509
510 m = self->tele_sector % self->tele_trackhead.sectors;
511 ++self->tele_sector;
512 for (n = 0; n < m; n++)
513 {
514 err = tele_readsechead(self);
515 if (err) return err;
516 err = tele_readsec(self, NULL);
517 if (err) return err;
518 }
519 err = tele_readsechead(self);
520 if (result)
521 {
522 result->fmt_cylinder = self->tele_sechead.cylinder_id;
523 result->fmt_head = self->tele_sechead.head_id;
524 result->fmt_sector = self->tele_sechead.sector_id;
525 result->fmt_secsize = self->tele_sechead.sector_len;
526 }
527 return DSK_ERR_OK;
528 }
tele_xseek(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head)529 dsk_err_t tele_xseek(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
530 dsk_pcyl_t cylinder, dsk_phead_t head)
531 {
532 return DSK_ERR_NOTIMPL;
533 }
534
535
tele_read(DSK_DRIVER * self,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)536 dsk_err_t tele_read(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
537 void *buf, dsk_pcyl_t cylinder,
538 dsk_phead_t head, dsk_psect_t sector)
539 {
540 return tele_xread(self, geom, buf, cylinder, head, cylinder,
541 dg_x_head(geom, head),
542 dg_x_sector(geom, head, sector), geom->dg_secsize, NULL);
543 }
544
545
tele_xread(DSK_DRIVER * s,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t sector_size,int * deleted)546 dsk_err_t tele_xread(DSK_DRIVER *s, const DSK_GEOMETRY *geom, void *buf,
547 dsk_pcyl_t cylinder, dsk_phead_t head,
548 dsk_pcyl_t cyl_expected,
549 dsk_phead_t head_expected,
550 dsk_psect_t sector, size_t sector_size,
551 int *deleted)
552 {
553 dsk_err_t err = DSK_ERR_OK;
554 unsigned char *secbuf;
555 size_t len = sector_size;
556 size_t sseclen;
557 int want_deleted = 0;
558 int try_again = 0;
559
560 DC_CHECK(s);
561
562 /* Single-sided? */
563 if (head > 0 && self->tele_head.sides < 2)
564 {
565 return DSK_ERR_NOADDR;
566 }
567
568 /* Check that the requested data rate is compatible. */
569 err = check_rate(self, geom); if (err) return err;
570 if (deleted && *deleted) want_deleted = 4;
571 do
572 {
573 err = tele_seeksec(self, geom, cylinder, head,
574 cyl_expected, head_expected,
575 sector, &len, &sseclen);
576 /* Are we retrying because we are looking for deleted data and found
577 * nondeleted or vice versa?
578 *
579 * If so, and we have run out of sectors in this track, AND we are on head 0,
580 * AND the disc has 2 heads, AND we are in multitrack mode, then look on head 1
581 * as well. Amazing.
582 * */
583 if (try_again == 1 && err == DSK_ERR_NOADDR)
584 {
585 err = DSK_ERR_NODATA;
586 if ((!geom->dg_nomulti) && head == 0 &&
587 self->tele_head.sides > 1)
588 {
589 head++;
590 sector = geom->dg_secbase;
591 continue;
592 }
593 }
594 try_again = 0;
595 if (err == DSK_ERR_NOADDR) self->tele_sector = 0;
596 if (err != DSK_ERR_DATAERR && err != DSK_ERR_OK)
597 return err;
598 /* We have the sector. But does it contain deleted data? */
599 if (deleted) *deleted = 0;
600 if ((self->tele_sechead.syndrome & 4) != want_deleted)
601 {
602 if (geom->dg_noskip)
603 {
604 if (deleted) *deleted = 1;
605 }
606 else
607 {
608 try_again = 1;
609 ++sector;
610 continue;
611 }
612 }
613 /* Read the whole sector into the buffer (if it's there) */
614 secbuf = dsk_malloc(sseclen);
615 if (!secbuf) return DSK_ERR_NOMEM;
616 err = tele_readsec(self, secbuf);
617 if (sseclen > sector_size) sseclen = sector_size;
618 memcpy(buf, secbuf, sseclen);
619 dsk_free(secbuf);
620 err = DSK_ERR_OK;
621 if (self->tele_sechead.syndrome & 2) err = DSK_ERR_DATAERR;
622 if (self->tele_sechead.syndrome & 32) err = DSK_ERR_NODATA;
623
624 }
625 while(try_again);
626
627 return err;
628 }
629
630
tele_xwrite(DSK_DRIVER * self,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t sector_size,int deleted)631 dsk_err_t tele_xwrite(DSK_DRIVER *self, const DSK_GEOMETRY *geom, const void *buf,
632 dsk_pcyl_t cylinder, dsk_phead_t head,
633 dsk_pcyl_t cyl_expected, dsk_phead_t head_expected,
634 dsk_psect_t sector, size_t sector_size, int deleted)
635 {
636 return DSK_ERR_RDONLY;
637 }
638
tele_trackids(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t * count,DSK_FORMAT ** result)639 dsk_err_t tele_trackids(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
640 dsk_pcyl_t cylinder, dsk_phead_t head,
641 dsk_psect_t *count, DSK_FORMAT **result)
642 {
643 return DSK_ERR_NOTIMPL;
644 }
645
tele_status(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_phead_t head,unsigned char * result)646 dsk_err_t tele_status(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
647 dsk_phead_t head, unsigned char *result)
648 {
649 return DSK_ERR_NOTIMPL;
650 }
651
tele_option_enum(DSK_DRIVER * self,int idx,char ** optname)652 dsk_err_t tele_option_enum(DSK_DRIVER *self, int idx, char **optname)
653 {
654 return DSK_ERR_NOTIMPL;
655 }
656
tele_option_set(DSK_DRIVER * self,const char * optname,int value)657 dsk_err_t tele_option_set(DSK_DRIVER *self, const char *optname, int value)
658 {
659 return DSK_ERR_NOTIMPL;
660 }
661
tele_option_get(DSK_DRIVER * self,const char * optname,int * value)662 dsk_err_t tele_option_get(DSK_DRIVER *self, const char *optname, int *value)
663 {
664 return DSK_ERR_NOTIMPL;
665 }
666
667 /* Don't bother to implement this one. Fall back on the standard version. */
tele_getgeom(DSK_DRIVER * self,DSK_GEOMETRY * dg)668 dsk_err_t tele_getgeom(DSK_DRIVER *self, DSK_GEOMETRY *dg)
669 {
670 return DSK_ERR_NOTIMPL;
671 }
672