OpenCBM
cbmcopy.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version
5  * 2 of the License, or (at your option) any later version.
6  *
7  * Copyright 2001 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
8  * Copyright 2011 Thomas Winkler
9  * Copyright 2011 Wolfgang Moser
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <assert.h>
16 #include "cbmcopy_int.h"
17 
18 #include "arch.h"
19 
20 static const unsigned char turboread1541[] = {
21 #include "turboread1541.inc"
22 };
23 
24 static const unsigned char turboread1571[] = {
25 #include "turboread1571.inc"
26 };
27 
28 static const unsigned char turboread1581[] = {
29 #include "turboread1581.inc"
30 };
31 
32 static const unsigned char turbowrite1541[] = {
33 #include "turbowrite1541.inc"
34 };
35 
36 static const unsigned char turbowrite1571[] = {
37 #include "turbowrite1571.inc"
38 };
39 
40 static const unsigned char turbowrite1581[] = {
41 #include "turbowrite1581.inc"
42 };
43 
44 extern transfer_funcs cbmcopy_s1_transfer,
45  cbmcopy_s2_transfer,
46  cbmcopy_pp_transfer,
47  cbmcopy_std_transfer;
48 
49 static struct _transfers
50 {
51  const transfer_funcs *trf;
52  const char *name, *abbrev;
53 }
54 transfers[] =
55 {
56  { &cbmcopy_s1_transfer, "auto", "a%1" },
57  { &cbmcopy_s1_transfer, "serial1", "s1" },
58  { &cbmcopy_s2_transfer, "serial2", "s2" },
59  { &cbmcopy_pp_transfer, "parallel", "p%" },
60  { &cbmcopy_std_transfer, "original", "o%" },
61  { NULL, NULL, NULL }
62 };
63 
64 static int check_drive_type(CBM_FILE fd, unsigned char drive,
65  cbmcopy_settings *settings,
66  cbmcopy_message_cb msg_cb)
67 {
68  const char *type_str;
69 
70  if( settings->drive_type == cbm_dt_unknown )
71  {
72  if(cbm_identify( fd, drive, &settings->drive_type, &type_str ))
73  {
74  msg_cb( sev_warning, "could not identify drive, using no turbo" );
75  }
76  else
77  {
78  msg_cb( sev_info, "identified a %s drive", type_str );
79  }
80  }
81  return 0;
82 }
83 
84 
85 static int send_turbo(CBM_FILE fd, unsigned char drive, int write,
86  const cbmcopy_settings *settings,
87  const unsigned char *turbo, size_t turbo_size,
88  const unsigned char *start_cmd, size_t cmd_len,
89  cbmcopy_message_cb msg_cb)
90 {
91  const transfer_funcs *trf;
92 
93  trf = transfers[settings->transfer_mode].trf;
94  /*
95  * minimum requirement for any transfer mode for a given device
96  * is that a transfer mode shutdown handler does exist
97  */
98  if(trf->exit_turbo != NULL)
99  {
100  if(turbo_size)
101  {
102  cbm_upload( fd, drive, 0x500, turbo, turbo_size );
103  msg_cb( sev_debug, "uploading %d bytes turbo code", turbo_size );
104  if(trf->upload_turbo(fd, drive, settings->drive_type, write) == 0)
105  {
106  cbm_exec_command( fd, drive, start_cmd, cmd_len );
107  msg_cb( sev_debug, "initializing transfer code" );
108  if(trf->start_turbo(fd, write) == 0)
109  {
110  msg_cb( sev_debug, "done" );
111  return 0;
112  }
113  else
114  {
115  msg_cb( sev_fatal, "could not start turbo" );
116  }
117  }
118  }
119  else
120  {
121  msg_cb( sev_debug, "no turbo code upload is required", turbo_size );
122  /* nevertheless the transfer must be initialised */
123  trf->upload_turbo(fd, drive, settings->drive_type, write);
124  trf->start_turbo(fd, write);
125  return 0;
126  }
127  }
128  else
129  {
130  msg_cb( sev_fatal, "Unsupported transfer mode for this device" );
131  }
132  return -1;
133 }
134 
135 
136 static int cbmcopy_read(CBM_FILE fd,
137  cbmcopy_settings *settings,
138  unsigned char drive,
139  int track, int sector,
140  const char *cbmname,
141  int cbmname_len,
142  unsigned char **filedata,
143  size_t *filedata_size,
144  cbmcopy_message_cb msg_cb,
145  cbmcopy_status_cb status_cb)
146 {
147  int rv;
148  int i;
149  int turbo_size;
150  int error;
151  unsigned char buf[48];
152  const unsigned char *turbo;
153  const transfer_funcs *trf;
154  int blocks_read;
155 
156  *filedata = NULL;
157  *filedata_size = 0;
158 
159  msg_cb( sev_debug, "using transfer mode '%s'",
160  transfers[settings->transfer_mode].name);
161  trf = transfers[settings->transfer_mode].trf;
162 
163  if(check_drive_type( fd, drive, settings, msg_cb ))
164  {
165  return -1;
166  }
167 
168  switch(settings->drive_type)
169  {
170  case cbm_dt_cbm1541:
171  turbo = turboread1541;
172  turbo_size = sizeof(turboread1541);
173  break;
174  case cbm_dt_cbm1570:
175  case cbm_dt_cbm1571:
176  cbm_exec_command( fd, drive, "U0>M1", 0 );
177  turbo = turboread1571;
178  turbo_size = sizeof(turboread1571);
179  break;
180  case cbm_dt_cbm1581:
181  turbo = turboread1581;
182  turbo_size = sizeof(turboread1581);
183  break;
184  default: /* unreachable */
185  msg_cb( sev_warning, "*** unknown drive type" );
186  /* fall through */
187  case cbm_dt_cbm4040:
188  case cbm_dt_cbm8050:
189  case cbm_dt_cbm8250:
190  case cbm_dt_sfd1001:
191  turbo = NULL;
192  turbo_size = 0;
193  break;
194  }
195 
196  if(transfers[settings->transfer_mode].abbrev[0] == 'o')
197  {
198  /* if "original" transfer mode - no drive code can be used */
199  turbo = NULL;
200  turbo_size = 0;
201  }
202 
203  if(cbmname)
204  {
205  /* start by file name */
206  track = 0;
207  sector = 0;
208  cbm_open( fd, drive, SA_READ, NULL, 0 );
209  if(cbmname_len == 0) cbmname_len = strlen( cbmname );
210  cbm_raw_write( fd, cbmname, cbmname_len );
211  cbm_unlisten( fd );
212  }
213  else
214  {
215  /* start by track/sector */
216  cbm_open( fd, drive, SA_READ, "#", 1 );
217  }
218  rv = cbm_device_status( fd, drive, (char*)buf, sizeof(buf) );
219 
220  if(rv)
221  {
222  msg_cb( sev_fatal, "could not open file for reading: %s", buf );
223  return rv;
224  }
225 
226  blocks_read = 0;
227  error = 0;
228 
229  if(track)
230  {
231  msg_cb( sev_debug, "start read at %d/%d", track, sector );
232  }
233  sprintf( (char*)buf, "U4:%c%c", (unsigned char)track, (unsigned char)sector );
234 
235  SETSTATEDEBUG((void)0); // pre send_turbo condition
236  if(send_turbo(fd, drive, 0, settings,
237  turbo, turbo_size, buf, 5, msg_cb) == 0)
238  {
239  msg_cb( sev_debug, "start of copy" );
240  status_cb( blocks_read );
241 
242  /*
243  * FIXME: Find and eliminate the real protocol races to
244  * eliminate the rare hangups with the 1581 based
245  * turbo routines (bugs suspected in 6502 code)
246  *
247  * Hotfix proposion for the 1581 protocols:
248  * add a little delay after the turbo start
249  */
250  arch_usleep(1000);
251 
252  SETSTATEDEBUG(DebugBlockCount=0); // turbo sent condition
253 
254  while( (error = trf->check_error(fd, 0)) == 0 )
255  {
256  SETSTATEDEBUG((void)0); // after check_error condition
257  arch_usleep(1000); // fix for Tim's environment
258 
259  SETSTATEDEBUG(DebugBlockCount++); // preset condition
260 
261  /* @SRT: FIXME! the next statement is dangerous: If there
262  * is no memory block large enough for reallocating, the
263  * memory block is not freed, but realloc() returns NULL,
264  * thus, we have a memory leak.
265  */
266  /* reserve additional memory to hold to up an additional full block */
267  *filedata = realloc(*filedata, *filedata_size + 254);
268  SETSTATEDEBUG((void)0); // after check_error condition
269  if(*filedata)
270  {
271  /* read block, let the block reader also handle the initial length byte */
272  i = trf->read_blk( fd, (*filedata) + blocks_read * 254, 254, msg_cb);
273  msg_cb( sev_debug, "number of bytes read for block %d: %d", blocks_read, i );
274 
275  SETSTATEDEBUG((void)0); // afterread condition
276 
277  /*
278  * FIXME: Find and eliminate the real protocol races to
279  * eliminate the rare hangups with the 1581 based
280  * turbo routines (bugs suspected in 6502 code)
281  *
282  * Hotfix proposion for the 1581 protocols:
283  * add a little delay at the end of the loop
284  * "hmmmm, if we know that the drive is busy
285  * now, shouldn't we wait for it then?"
286  * add a little delay after the turbo start
287  */
288  arch_usleep(1000);
289 
290  if( i < 255)
291  {
292  if( i >= 0 )
293  {
294  /* in case of original transfers, there is no extra length byte transfer, */
295  /* whenever 254 bytes are read from a block a count value of 255 is returned */
296  /* and if this was the last block, 0 bytes are read with the next block call */
297  *filedata_size += i;
298  }
299  else
300  {
301  rv = -1;
302  }
303  break;
304  }
305  else
306  {
307  /* more blocks are following, a full block was transferred */
308  *filedata_size += 254;
309  }
310 
311  SETSTATEDEBUG((void)0); // afterread condition
312  status_cb( ++blocks_read );
313  }
314  else
315  {
316  SETSTATEDEBUG((void)0); // afterread condition
317  /* FIXME */
318  }
319  }
320  msg_cb( sev_debug, "done" );
321  SETSTATEDEBUG(DebugBlockCount=-1); // turbo sent condition
322  trf->exit_turbo( fd, 0 );
323  SETSTATEDEBUG((void)0); // turbo exited condition
324 
325  /*
326  * FIXME: Find and eliminate the real protocol race to
327  * eliminate a rare "99, DRIVER ERROR,00,00" with the
328  * 1571 disk drive and the serial-2 read turbo
329  *
330  * Hotfix proposion for the 1571 protocol:
331  * add a listen/unlisten sequence, just doing a decent
332  * arch_usleep() and waiting some time did not work
333  */
334  cbm_listen(fd, drive, SA_READ);
335  cbm_unlisten(fd);
336  SETSTATEDEBUG((void)0); // turbo exited, waited for drive
337 
338  rv = cbm_device_status( fd, drive, (char*)buf, sizeof(buf) );
339  if(rv)
340  {
341  msg_cb( sev_warning, "file copy ended with error status: %s", buf );
342  }
343  }
344 
345  cbm_close( fd, drive, SA_READ );
346  return rv;
347 }
348 
349 
350 char *cbmcopy_get_transfer_modes()
351 {
352  const struct _transfers *t;
353  int size;
354  char *buf;
355  char *dst;
356 
357  size = 1; /* for terminating '\0' */
358  for(t = transfers; t->name; t++)
359  {
360  size += (strlen(t->name) + 1);
361  }
362 
363  buf = malloc(size);
364 
365  if(buf)
366  {
367  dst = buf;
368  for(t = transfers; t->name; t++)
369  {
370  strcpy(dst, t->name);
371  dst += (strlen(t->name) + 1);
372  }
373  *dst = '\0';
374  }
375 
376  return buf;
377 }
378 
379 
380 int cbmcopy_get_transfer_mode_index(const char *name)
381 {
382  const struct _transfers *t;
383  int i;
384  int abbrev_len;
385  int tm_len;
386 
387  if(NULL == name)
388  {
389  /* default transfer mode */
390  return 0;
391  }
392 
393  tm_len = strlen(name);
394  for(i = 0, t = transfers; t->name; i++, t++)
395  {
396  if(strcmp(name, t->name) == 0)
397  {
398  /* full match */
399  return i;
400  }
401  if(t->abbrev[strlen(t->abbrev)-1] == '%')
402  {
403  abbrev_len = strlen(t->abbrev) - 1;
404  if(abbrev_len <= tm_len && strncmp(t->name, name, tm_len) == 0)
405  {
406  return i;
407  }
408  }
409  else
410  {
411  if(strcmp(name, t->abbrev) == 0)
412  {
413  return i;
414  }
415  }
416  }
417  return -1;
418 }
419 
420 int cbmcopy_check_auto_transfer_mode(CBM_FILE cbm_fd, int auto_transfermode, int drive)
421 {
422  /* We assume auto is the first transfer mode */
423  assert(strcmp(transfers[0].name, "auto") == 0);
424 
425  if (auto_transfermode == 0)
426  {
427  enum cbm_cable_type_e cable_type;
428  enum cbm_device_type_e device_type;
429  unsigned char testdrive;
430 
431  /*
432  * Test the cable
433  */
434 
435  if (cbm_identify_xp1541(cbm_fd, (unsigned char)drive, NULL, &cable_type) == 0)
436  {
437  if (cable_type == cbm_ct_xp1541)
438  {
439  /*
440  * We have a parallel cable, use that
441  */
442  return cbmcopy_get_transfer_mode_index("parallel");
443  }
444  }
445 
446  /*
447  * lookup drivetyp, if IEEE-488 drive, use original
448  */
449 
450  if (cbm_identify(cbm_fd, (unsigned char)drive, &device_type, NULL) == 0)
451  {
452  switch(device_type)
453  {
454  case cbm_dt_cbm4040:
455  case cbm_dt_cbm8050:
456  case cbm_dt_cbm8250:
457  case cbm_dt_sfd1001:
458  /*
459  * We are using an IEEE-488 drive, use original transfer mode
460  */
461  return cbmcopy_get_transfer_mode_index("original");
462 
463  default:
464  /*
465  * We are using an IEC drive, everything is o.k.
466  */
467  break;
468  }
469  }
470 
471  /*
472  * We do not have a parallel cable. Check if we are the only drive
473  * on the bus, so we can use serial2, at least.
474  */
475 
476  for (testdrive = 4; testdrive < 31; ++testdrive)
477  {
478  /* of course, the drive to be transfered to is present! */
479  if (testdrive == drive)
480  continue;
481 
482  if (cbm_identify(cbm_fd, testdrive, &device_type, NULL) == 0)
483  {
484  /*
485  * My bad, there is another drive -> only use serial1
486  */
487  return cbmcopy_get_transfer_mode_index("serial1");
488  }
489  }
490 
491  /*
492  * If we reached here with transfermode 0, we are the only
493  * drive, thus, use serial2.
494  */
495  return cbmcopy_get_transfer_mode_index("serial2");
496  }
497 
498  return auto_transfermode;
499 }
500 
501 cbmcopy_settings *cbmcopy_get_default_settings(void)
502 {
503  cbmcopy_settings *settings;
504 
505  settings = malloc(sizeof(cbmcopy_settings));
506 
507  if(NULL != settings)
508  {
509  settings->drive_type = cbm_dt_unknown; /* auto detect later on */
510  settings->transfer_mode = 0;
511  }
512  return settings;
513 }
514 
515 
516 
517 int cbmcopy_write_file(CBM_FILE fd,
518  cbmcopy_settings *settings,
519  int drivei,
520  const char *cbmname,
521  int cbmname_len,
522  const unsigned char *filedata,
523  int filedata_size,
524  cbmcopy_message_cb msg_cb,
525  cbmcopy_status_cb status_cb)
526 {
527  int rv;
528  int i;
529  int turbo_size;
530  unsigned char drive = (unsigned char) drivei;
531  int error;
532  unsigned char buf[48];
533  const unsigned char *turbo;
534  const transfer_funcs *trf;
535  int blocks_written;
536 
537  msg_cb( sev_debug, "using transfer mode `%s'",
538  transfers[settings->transfer_mode].name);
539  trf = transfers[settings->transfer_mode].trf;
540 
541  if(check_drive_type( fd, drive, settings, msg_cb ))
542  {
543  return -1;
544  }
545 
546  switch(settings->drive_type)
547  {
548  case cbm_dt_cbm1541:
549  turbo = turbowrite1541;
550  turbo_size = sizeof(turbowrite1541);
551  break;
552  case cbm_dt_cbm1570:
553  case cbm_dt_cbm1571:
554  cbm_exec_command( fd, drive, "U0>M1", 0 );
555  turbo = turbowrite1571;
556  turbo_size = sizeof(turbowrite1571);
557  break;
558  case cbm_dt_cbm1581:
559  turbo = turbowrite1581;
560  turbo_size = sizeof(turbowrite1581);
561  break;
562  default: /* unreachable */
563  msg_cb( sev_warning, "*** unknown drive type" );
564  /* fall through */
565  case cbm_dt_cbm4040:
566  case cbm_dt_cbm8050:
567  case cbm_dt_cbm8250:
568  case cbm_dt_sfd1001:
569  turbo = NULL;
570  turbo_size = 0;
571  break;
572  }
573 
574  if(transfers[settings->transfer_mode].abbrev[0] == 'o')
575  {
576  /* if "original" transfer mode - no drive code can be used */
577  turbo = NULL;
578  turbo_size = 0;
579  }
580 
581  cbm_open( fd, drive, SA_WRITE, NULL, 0 );
582  if(cbmname_len == 0) cbmname_len = strlen( cbmname );
583  cbm_raw_write( fd, cbmname, cbmname_len );
584  cbm_unlisten( fd );
585  rv = cbm_device_status( fd, drive, buf, sizeof(buf) );
586 
587  if(rv)
588  {
589  msg_cb( sev_fatal, "could not open file for writing: %s", buf );
590  return rv;
591  }
592 
593  blocks_written = 0;
594  error = 0;
595 
596  SETSTATEDEBUG((void)0); // pre send_turbo condition
597  if(send_turbo(fd, drive, 1, settings,
598  turbo, turbo_size, (unsigned char*)"U4:", 3, msg_cb) == 0)
599  {
600  msg_cb( sev_debug, "start of copy" );
601  status_cb( blocks_written );
602 
603  /*
604  * FIXME: Find and eliminate the real protocol races to
605  * eliminate the rare hangups with the 1581 based
606  * turbo routines (bugs suspected in 6502 code)
607  *
608  * Hotfix proposion for the 1581 protocols:
609  * add a little delay after the turbo start
610  */
611  arch_usleep(1000);
612 
613  SETSTATEDEBUG(DebugBlockCount=0); // turbo sent condition
614 
615  while( filedata_size > 0 )
616  {
617  /* if more blocks are following (more than 254 bytes) set the count value to 255 */
618  i = filedata_size <= 254 ? filedata_size : 255;
619 
620  SETSTATEDEBUG(DebugBlockCount++);
621 
622  /* write block, let the block writer also handle the initial length byte */
623  i = trf->write_blk( fd, filedata, (unsigned char)i, msg_cb );
624  if ( (i != 254) && (i != filedata_size) )
625  {
626  /* normally blocks of 254 bytes are written, even if the count byte is at value 255 */
627  /* for the last block of a file, only filedata_size bytes need to be transferred */
628  rv = -1;
629  break;
630  }
631 
632  SETSTATEDEBUG((void)0);
633  if ( trf->check_error( fd, 1 ) != 0 )
634  {
635  rv = -1;
636  break;
637  }
638 
639  /*
640  * FIXME: Find and eliminate the real protocol races to
641  * eliminate the rare hangups with the 1581 based
642  * turbo routines (bugs suspected in 6502 code)
643  *
644  * Hotfix proposion for the 1581 protocols:
645  * add a little delay at the end of the loop
646  * "hmmmm, if we know that the drive is busy
647  * now, shouldn't we wait for it then?"
648  * add a little delay after the turbo start
649  */
650  arch_usleep(1000);
651 
652  status_cb( ++blocks_written );
653  SETSTATEDEBUG((void)0);
654 
655  filedata_size -= 254;
656  filedata += 254;
657  }
658  msg_cb( sev_debug, "done" );
659 
660  SETSTATEDEBUG((void)0);
661  trf->exit_turbo( fd, 1 );
662  SETSTATEDEBUG((void)0);
663 
664  rv = cbm_device_status( fd, drive, (char*)buf, sizeof(buf) );
665  if(rv)
666  {
667  msg_cb( sev_warning, "file copy ended with error status: %s", buf );
668  }
669  }
670  cbm_close( fd, drive, SA_WRITE );
671  return rv;
672 }
673 
674 
675 /* just a wrapper */
676 int cbmcopy_read_file_ts(CBM_FILE fd,
677  cbmcopy_settings *settings,
678  int drive,
679  int track, int sector,
680  unsigned char **filedata,
681  size_t *filedata_size,
682  cbmcopy_message_cb msg_cb,
683  cbmcopy_status_cb status_cb)
684 {
685  return cbmcopy_read(fd, settings, (unsigned char) drive,
686  track, sector,
687  NULL, 0,
688  filedata, filedata_size,
689  msg_cb, status_cb);
690 }
691 
692 
693 /* just a wrapper */
694 int cbmcopy_read_file(CBM_FILE fd,
695  cbmcopy_settings *settings,
696  int drive,
697  const char *cbmname,
698  int cbmname_len,
699  unsigned char **filedata,
700  size_t *filedata_size,
701  cbmcopy_message_cb msg_cb,
702  cbmcopy_status_cb status_cb)
703 {
704  return cbmcopy_read(fd, settings, (unsigned char) drive,
705  0, 0,
706  cbmname, cbmname_len,
707  filedata, filedata_size,
708  msg_cb, status_cb);
709 }
710 
734 int write_block_generic(CBM_FILE HandleDevice, const void *data, unsigned char size, write_byte_t wb_func, cbmcopy_message_cb msg_cb)
735 {
736  int rv = 0;
737  const unsigned char *pbuffer = data;
738 
739  SETSTATEDEBUG((void)0);
740 #ifdef LIBCBMCOPY_DEBUG
741  msg_cb( sev_debug, "send byte count: %d", size );
742 #endif
743  if ( (pbuffer == NULL) || (wb_func( HandleDevice, size ) != 0) )
744  {
745  return -1;
746  }
747 
748  SETSTATEDEBUG(DebugByteCount=0);
749  if( size == 0xff )
750  {
751  size--;
752  }
753 
754 #ifdef LIBCBMCOPY_DEBUG
755  msg_cb( sev_debug, "send block data" );
756 #endif
757  while( size>0 )
758  {
759  SETSTATEDEBUG(DebugByteCount++);
760  if ( wb_func( HandleDevice, *(pbuffer++) ) != 0 )
761  {
762  break;
763  }
764  rv++;
765  size--;
766  }
767 
768  /* (drive is busy now) */
769  SETSTATEDEBUG(DebugByteCount=-1);
770 
771  return rv;
772 }
773 
796 int read_block_generic(CBM_FILE HandleDevice, void *data, size_t size, read_byte_t rb_func, cbmcopy_message_cb msg_cb)
797 {
798  int rv = 0;
799  unsigned char c;
800  unsigned char *pbuffer = data;
801 
802  SETSTATEDEBUG((void)0);
803  /* get the number of bytes that need to be transferred for this block */
804  c = rb_func( HandleDevice );
805  SETSTATEDEBUG((void)0);
806 #ifdef LIBCBMCOPY_DEBUG
807  msg_cb( sev_debug, "received byte count: %d", c );
808 #endif
809 
810  rv = c;
811  if( c == 0xff )
812  {
813  /* this is a flag that further bytes are following, so get a full block of 254 bytes */
814  c--;
815  }
816 
817  if( (pbuffer == NULL) || (c > size) )
818  {
819  /* If the block size if greater than the available buffer, return with
820  * a fatal error since the turbo handlers always need to transfer a
821  * complete block. If there is no buffer allocated at all, fail also.
822  */
823  return -1;
824  }
825 
826  SETSTATEDEBUG(DebugByteCount=0);
827 #ifdef LIBCBMCOPY_DEBUG
828  msg_cb( sev_debug, "receive block data (%d)", c );
829 #endif
830  while( c>0 )
831  {
832  SETSTATEDEBUG(DebugByteCount++);
833  *(pbuffer++) = rb_func( HandleDevice );
834  c--;
835  }
836 
837  /* (drive is busy now) */
838  SETSTATEDEBUG(DebugByteCount=-1);
839 
840  return rv;
841 }
int CBMAPIDECL cbm_identify_xp1541(CBM_FILE HandleDevice, unsigned char DeviceAddress, enum cbm_device_type_e *CbmDeviceType, enum cbm_cable_type_e *CableType)
Identify the cable connected to a specific floppy drive.
Definition: detectxp1541.c:187
int CBMAPIDECL cbm_listen(CBM_FILE HandleDevice, unsigned char DeviceAddress, unsigned char SecondaryAddress)
Send a LISTEN on the IEC serial bus.
Definition: cbm.c:945
int CBMAPIDECL cbm_device_status(CBM_FILE HandleDevice, unsigned char DeviceAddress, void *Buffer, size_t BufferLength)
Read the drive status from a floppy.
Definition: cbm.c:1525
int CBMAPIDECL cbm_close(CBM_FILE HandleDevice, unsigned char DeviceAddress, unsigned char SecondaryAddress)
Close a file on the IEC serial bus.
Definition: cbm.c:1072
int CBMAPIDECL cbm_raw_write(CBM_FILE HandleDevice, const void *Buffer, size_t Count)
Write data to the IEC serial bus.
Definition: cbm.c:870
#define CBM_FILE
Definition: opencbm.h:87
int CBMAPIDECL cbm_unlisten(CBM_FILE HandleDevice)
Send an UNLISTEN on the IEC serial bus.
Definition: cbm.c:1100
int CBMAPIDECL cbm_open(CBM_FILE HandleDevice, unsigned char DeviceAddress, unsigned char SecondaryAddress, const void *Filename, size_t FilenameLength)
Open a file on the IEC serial bus.
Definition: cbm.c:1012
int CBMAPIDECL cbm_exec_command(CBM_FILE HandleDevice, unsigned char DeviceAddress, const void *Command, size_t Size)
Executes a command in the floppy drive.
Definition: cbm.c:1599
cbm_device_type_e
Definition: opencbm.h:114
int CBMAPIDECL cbm_identify(CBM_FILE HandleDevice, unsigned char DeviceAddress, enum cbm_device_type_e *CbmDeviceType, const char **CbmDeviceString)
Identify the connected floppy drive.
Definition: detect.c:66
cbm_cable_type_e
Definition: opencbm.h:132
Define makros and functions which account for differences between the different architectures.
int CBMAPIDECL cbm_upload(CBM_FILE HandleDevice, unsigned char DeviceAddress, int DriveMemAddress, const void *Program, size_t Size)
Upload a program into a floppy's drive memory.
Definition: upload.c:133