OpenCBM
libd64copy/pp.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 1999 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
8  * Copyright 2008 Spiro Trikaliotis
9 */
10 
11 #include "opencbm.h"
12 #include "d64copy_int.h"
13 
14 #include <stdlib.h>
15 
16 #include "arch.h"
17 
18 #include "opencbm-plugin.h"
19 
21 
23 
24 enum pp_direction_e
25 {
26  PP_READ, PP_WRITE
27 };
28 
29 static CBM_FILE fd_cbm;
30 static int two_sided;
31 
32 static const unsigned char pp1541_drive_prog[] = {
33 #include "pp1541.inc"
34 };
35 
36 static const unsigned char pp1571_drive_prog[] = {
37 #include "pp1571.inc"
38 };
39 
40 static void pp_check_direction(enum pp_direction_e dir)
41 {
42  static enum pp_direction_e direction = PP_READ;
43  if(direction != dir)
44  {
45  arch_usleep(100);
46  direction = dir;
47  }
48 }
49 
50 static int pp_write(CBM_FILE fd, char c1, char c2)
51 {
52  SETSTATEDEBUG((void)0);
53  pp_check_direction(PP_WRITE);
54  SETSTATEDEBUG((void)0);
55 #ifndef USE_CBM_IEC_WAIT
56  while(!cbm_iec_get(fd, IEC_DATA));
57 #else
58  cbm_iec_wait(fd, IEC_DATA, 1);
59 #endif
60  SETSTATEDEBUG((void)0);
61  cbm_pp_write(fd, c1);
62  SETSTATEDEBUG((void)0);
64 
65  SETSTATEDEBUG((void)0);
66 #ifndef USE_CBM_IEC_WAIT
67  while(cbm_iec_get(fd, IEC_DATA));
68 #else
69  cbm_iec_wait(fd, IEC_DATA, 0);
70 #endif
71  SETSTATEDEBUG((void)0);
72  cbm_pp_write(fd, c2);
73  SETSTATEDEBUG((void)0);
75 
76  SETSTATEDEBUG((void)0);
77  return 0;
78 }
79 
80 /* write_n redirects USB writes to the external reader if required */
81 static void write_n(const unsigned char *data, int size)
82 {
83  int i;
84 
86  {
87  opencbm_plugin_pp_dc_write_n(fd_cbm, data, size);
88  return;
89  }
90 
91  for(i=0;i<size/2;i++,data+=2)
92  pp_write(fd_cbm, data[0], data[1]);
93 }
94 
95 static int pp_read(CBM_FILE fd, unsigned char *c1, unsigned char *c2)
96 {
97  SETSTATEDEBUG((void)0);
98  pp_check_direction(PP_READ);
99  SETSTATEDEBUG((void)0);
100 #ifndef USE_CBM_IEC_WAIT
101  while(!cbm_iec_get(fd, IEC_DATA));
102 #else
103  cbm_iec_wait(fd, IEC_DATA, 1);
104 #endif
105  SETSTATEDEBUG((void)0);
106  *c1 = cbm_pp_read(fd);
107  SETSTATEDEBUG((void)0);
109 
110  SETSTATEDEBUG((void)0);
111 #ifndef USE_CBM_IEC_WAIT
112  while(cbm_iec_get(fd, IEC_DATA));
113 #else
114  cbm_iec_wait(fd, IEC_DATA, 0);
115 #endif
116  SETSTATEDEBUG((void)0);
117  *c2 = cbm_pp_read(fd);
118  SETSTATEDEBUG((void)0);
119  cbm_iec_set(fd, IEC_CLOCK);
120 
121  SETSTATEDEBUG((void)0);
122  return 0;
123 }
124 
125 /* read_n redirects USB reads to the external reader if required */
126 static void read_n(unsigned char *data, int size)
127 {
128  int i;
129 
131  {
132  opencbm_plugin_pp_dc_read_n(fd_cbm, data, size);
133  return;
134  }
135 
136  for(i=0;i<size/2;i++,data+=2)
137  pp_read(fd_cbm, data, data+1);
138 }
139 
140 static int read_block(unsigned char tr, unsigned char se, unsigned char *block)
141 {
142  unsigned char status[2];
143  SETSTATEDEBUG((void)0);
144 
145  status[0] = tr; status[1] = se;
146  write_n(status, 2);
147 
148 #ifndef USE_CBM_IEC_WAIT
149  arch_usleep(20000);
150 #endif
151  SETSTATEDEBUG((void)0);
152  read_n(status, 2);
153 
154  SETSTATEDEBUG(DebugByteCount=0);
155  read_n(block, BLOCKSIZE);
156  SETSTATEDEBUG(DebugByteCount=-1);
157 
158  SETSTATEDEBUG((void)0);
159  return status[1];
160 }
161 
162 static int write_block(unsigned char tr, unsigned char se, const unsigned char *blk, int size, int read_status)
163 {
164  int i = 0;
165  unsigned char status[2];
166 
167  SETSTATEDEBUG((void)0);
168  status[0] = tr; status[1] = se;
169  write_n(status, 2);
170 
171  SETSTATEDEBUG((void)0);
172  /* send first byte twice if length is odd */
173  if(size % 2) {
174  write_n(blk, 2);
175  i = 1;
176  }
177  SETSTATEDEBUG(DebugByteCount=0);
178  write_n(blk+i, size-i);
179 
180  SETSTATEDEBUG(DebugByteCount=-1);
181 #ifndef USE_CBM_IEC_WAIT
182  if(size == BLOCKSIZE) {
183  arch_usleep(20000);
184  }
185 #endif
186 
187  SETSTATEDEBUG((void)0);
188  read_n(status, 2);
189 
190  SETSTATEDEBUG((void)0);
191  return status[1];
192 }
193 
194 static int open_disk(CBM_FILE fd, d64copy_settings *settings,
195  const void *arg, int for_writing,
196  turbo_start start, d64copy_message_cb message_cb)
197 {
198  unsigned char d = (unsigned char)(ULONG_PTR)arg;
199  const unsigned char *drive_prog;
200  int prog_size;
201 
202  fd_cbm = fd;
203  two_sided = settings->two_sided;
204 
205  opencbm_plugin_pp_dc_read_n = cbm_get_plugin_function_address("opencbm_plugin_pp_dc_read_n");
206 
207  opencbm_plugin_pp_dc_write_n = cbm_get_plugin_function_address("opencbm_plugin_pp_dc_write_n");
208 
209  if(settings->drive_type != cbm_dt_cbm1541)
210  {
211  drive_prog = pp1571_drive_prog;
212  prog_size = sizeof(pp1571_drive_prog);
213  }
214  else
215  {
216  drive_prog = pp1541_drive_prog;
217  prog_size = sizeof(pp1541_drive_prog);
218  }
219 
220  SETSTATEDEBUG((void)0);
221  /* make sure the XP1541 portion of the cable is in input mode */
222  cbm_pp_read(fd_cbm);
223 
224  SETSTATEDEBUG((void)0);
225  cbm_upload(fd_cbm, d, 0x700, drive_prog, prog_size);
226  SETSTATEDEBUG((void)0);
227  start(fd, d);
228  SETSTATEDEBUG((void)0);
229  pp_check_direction(PP_READ);
230  SETSTATEDEBUG((void)0);
231  cbm_iec_set(fd_cbm, IEC_CLOCK);
232  SETSTATEDEBUG((void)0);
233  cbm_iec_wait(fd_cbm, IEC_DATA, 1);
234  SETSTATEDEBUG((void)0);
235  return 0;
236 }
237 
238 static void close_disk(void)
239 {
240  SETSTATEDEBUG((void)0);
241  pp_write(fd_cbm, 0, 0);
242  arch_usleep(100);
243  SETSTATEDEBUG((void)0);
244  cbm_iec_wait(fd_cbm, IEC_DATA, 0);
245 
246  /* make sure the XP1541 portion of the cable is in input mode */
247  SETSTATEDEBUG((void)0);
248  cbm_pp_read(fd_cbm);
249  SETSTATEDEBUG((void)0);
250 
252 
254 }
255 
256 static int send_track_map(unsigned char tr, const char *trackmap, unsigned char count)
257 {
258  int i, size;
259  unsigned char *data;
260 
261  size = d64copy_sector_count(two_sided, tr);
262  data = malloc(2+2*size);
263 
264  data[0] = tr;
265  data[1] = count;
266 
267  /* build track map */
268  for(i = 0; i < size; i++)
269  data[2+2*i] = data[2+2*i+1] = !NEED_SECTOR(trackmap[i]);
270 
271  write_n(data, 2*size+2);
272  free(data);
273  SETSTATEDEBUG((void)0);
274  return 0;
275 }
276 
277 static int read_gcr_block(unsigned char *se, unsigned char *gcrbuf)
278 {
279  unsigned char s[2];
280  SETSTATEDEBUG((void)0);
281  read_n(s, 2);
282  *se = s[1];
283  SETSTATEDEBUG((void)0);
284  read_n(s, 2);
285 
286  if(s[1]) {
287  return s[1];
288  }
289  SETSTATEDEBUG(DebugByteCount=0);
290  read_n(gcrbuf, GCRBUFSIZE);
291  SETSTATEDEBUG(DebugByteCount=-1);
292 
293  SETSTATEDEBUG((void)0);
294  return 0;
295 }
296 
297 DECLARE_TRANSFER_FUNCS_EX(pp_transfer, 1, 1);
int CBMAPIDECL opencbm_plugin_pp_dc_read_n_t(CBM_FILE HandleDevice, unsigned char *data, unsigned int size)
read a block of data from the OpenCBM backend with protocol parallel/d64copy
unsigned char CBMAPIDECL cbm_pp_read(CBM_FILE HandleDevice)
Read a byte from a XP1541/XP1571 cable.
Definition: cbm.c:1244
Plugin DLL interface.
#define IEC_DATA
Definition: opencbm.h:97
void CBMAPIDECL cbm_iec_set(CBM_FILE HandleDevice, int Line)
Activate a line on the IEC serial bus.
Definition: cbm.c:1341
int CBMAPIDECL cbm_iec_get(CBM_FILE HandleDevice, int Line)
Get the (logical) state of a line on the IEC serial bus.
Definition: cbm.c:1477
#define CBM_FILE
Definition: opencbm.h:87
void CBMAPIDECL cbm_iec_release(CBM_FILE HandleDevice, int Line)
Deactivate a line on the IEC serial bus.
Definition: cbm.c:1372
int CBMAPIDECL opencbm_plugin_pp_dc_read_n(CBM_FILE HandleDevice, unsigned char *data, unsigned int size)
Read data with parallel protocol (d64copy)
int CBMAPIDECL cbm_iec_wait(CBM_FILE HandleDevice, int Line, int State)
Wait for a line to have a specific state.
Definition: cbm.c:1448
DLL interface for accessing the driver.
Define makros and functions which account for differences between the different architectures.
int CBMAPIDECL opencbm_plugin_pp_dc_write_n(CBM_FILE HandleDevice, const unsigned char *data, unsigned int size)
Write data with parallel protocol (d64copy)
int CBMAPIDECL opencbm_plugin_pp_dc_write_n_t(CBM_FILE HandleDevice, const unsigned char *data, unsigned int size)
write a block of data to the OpenCBM backend with protocol parallel/d64copy
void *CBMAPIDECL cbm_get_plugin_function_address(const char *Functionname)
Get the function pointer for a function in a plugin.
Definition: cbm.c:2449
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
void CBMAPIDECL cbm_pp_write(CBM_FILE HandleDevice, unsigned char Byte)
Write a byte to a XP1541/XP1571 cable.
Definition: cbm.c:1282
#define IEC_CLOCK
Definition: opencbm.h:98