ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/writecbm.c
Revision: 1.1
Committed: 2004-01-07T15:37:45Z (20 years, 2 months ago) by cebix
Content type: text/plain
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# Content
1 /*
2 * writecbm.c - Write CBM disk from image file with the Catweasel controller
3 *
4 * Written in 2003 by Christian Bauer <Christian.Bauer@uni-mainz.de>
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <sys/io.h>
14
15 #include "catweasel.h"
16 #include "common.h"
17
18
19 /* Number of sync GCR bytes */
20 #define SYNC_LENGTH 5
21
22 /* Number of header gap GCR bytes */
23 #define HEADER_GAP_LENGTH 9
24
25 /* Number of inter-sector gap GCR bytes */
26 #define GAP_LENGTH 4
27
28
29 /* Write byte to Catweasel buffer */
30 #define PUT(x) put_precomp(x)
31
32 static void put_precomp(unsigned char x)
33 {
34 static int previous = 0, adjust = 0;
35 int newadjust = (previous > 1) - (x > 1);
36
37 outb(0x80 - clock_table[previous] - adjust - newadjust, c.io_mem);
38 previous = x;
39 adjust = -newadjust;
40 }
41
42
43 /*
44 * We take advantage of the fact that all GCR nybbles (5 bits) end in "x1"
45 * or "10", so there is either one or no "0"-bit before the next nybble.
46 * This table stores the sequence of distances between "1"-bits for each
47 * possible 4-bit value. The end marker is -1 if the trailing bit is 1,
48 * and -2 if it is 0. In the latter case, the first distance value for
49 * the next nybble must be incremented by 1.
50 */
51
52 static const int bin2gcr[16 * 5] = {
53 2, 2, -2, 0, 0, // 01010
54 2, 2, 1, -1, 0, // 01011
55 1, 3, -2, 0, 0, // 10010
56 1, 3, 1, -1, 0, // 10011
57 2, 1, 1, -2, 0, // 01110
58 2, 1, 1, 1, -1, // 01111
59 1, 2, 1, -2, 0, // 10110
60 1, 2, 1, 1, -1, // 10111
61 2, 3, -1, 0, 0, // 01001
62 1, 1, 3, -1, 0, // 11001
63 1, 1, 2, -2, 0, // 11010
64 1, 1, 2, 1, -1, // 11011
65 2, 1, 2, -1, 0, // 01101
66 1, 1, 1, 2, -1, // 11101
67 1, 1, 1, 1, -2, // 11110
68 1, 2, 2, -1, 0 // 10101
69 };
70
71 /* Encode one nybble */
72 static void encode_nybble(int x, int *trailing_zero)
73 {
74 const int *gcr = bin2gcr + x * 5;
75 int v;
76
77 do {
78 v = *gcr++;
79 if (v > 0)
80 PUT(v + *trailing_zero);
81 *trailing_zero = (v == -2) ? 1 : 0;
82 } while (v > 0);
83 }
84
85 /* Encode GCR data from specified buffer */
86 static void encode_gcr(const unsigned char *p, int num)
87 {
88 int trailing_zero = 0;
89
90 while (num > 0) {
91
92 // Read byte from buffer
93 unsigned char x = *p++;
94 num--;
95
96 // Encode upper and lower nybbles
97 encode_nybble(x >> 4, &trailing_zero);
98 encode_nybble(x & 0x0f, &trailing_zero);
99 }
100 }
101
102
103 /* Encode sector header */
104 static void encode_header(int track, int sector, unsigned char id1, unsigned char id2)
105 {
106 unsigned char header[8];
107 int i;
108
109 // Set up header data
110 header[0] = 0x08;
111 header[2] = sector;
112 header[3] = track;
113 header[4] = id2;
114 header[5] = id1;
115 header[6] = 0x0f;
116 header[7] = 0x0f;
117 header[1] = header[2] ^ header[3] ^ header[4] ^ header[5];
118
119 // Write sync
120 for (i = 0; i < SYNC_LENGTH * 8; i++)
121 PUT(1);
122
123 // Write header
124 encode_gcr(header, 8);
125
126 // Write header gap
127 for (i = 0; i < HEADER_GAP_LENGTH * 4; i++)
128 PUT(2);
129 }
130
131
132 /* Encode sector data from specified buffer */
133 static void encode_data(int track, const unsigned char *p)
134 {
135 unsigned char tmp[SECTOR_SIZE + 4];
136 int i, sum = 0;
137
138 // Set up sector data
139 tmp[0] = 0x07;
140 memcpy(tmp + 1, p, SECTOR_SIZE);
141 for (i = 0; i < SECTOR_SIZE; i++)
142 sum ^= p[i];
143 tmp[SECTOR_SIZE + 1] = sum;
144 tmp[SECTOR_SIZE + 2] = 0;
145 tmp[SECTOR_SIZE + 3] = 0;
146
147 // Write sync
148 for (i = 0; i < SYNC_LENGTH * 8; i++)
149 PUT(1);
150
151 // Write data
152 encode_gcr(tmp, SECTOR_SIZE + 4);
153
154 // Write inter-sector gap
155 for (i = 0; i < GAP_LENGTH * 4; i++)
156 PUT(2);
157 }
158
159
160 /* Encode sectors from track_buf */
161 static void encode_sectors(int track)
162 {
163 int sector;
164
165 // Encode each sector
166 for (sector = 0; sector < num_sectors[track]; sector++) {
167 encode_header(track, sector, 0x41, 0x41);
168 encode_data(track, track_buf + SECTOR_SIZE * sector);
169 }
170 }
171
172
173 /* Write one track from track_buf, returns 0 on error */
174 static int write_track(int drive, int track)
175 {
176 int i;
177
178 // Set speed zone and tables
179 set_zone(track);
180
181 // Seek to track
182 catweasel_seek(c.drives + drive, (track - 1) * (double_step + 1));
183 msdelay(20);
184
185 // Write empty track
186 inb(c.iobase + 1);
187 for (i = 0; i < bps[std_speed[track]] * 60 / drive_rpm; i++)
188 PUT(2);
189 outb(0xff, c.io_mem);
190 if (!catweasel_write(c.drives + drive, 0, 1, 1100 * 60 / drive_rpm)) {
191 fprintf(stderr, "Error writing track %d\n", track);
192 return 0;
193 }
194
195 // Reset buffer pointer
196 inb(c.iobase + 1);
197
198 // Encode all sectors
199 encode_sectors(track);
200
201 // Write to disk (1 revolution + 10%)
202 outb(0xff, c.io_mem);
203 if (!catweasel_write(c.drives + drive, 0, 1, 1100 * 60 / drive_rpm)) {
204 fprintf(stderr, "Error writing track %d\n", track);
205 return 0;
206 }
207
208 return 1;
209 }
210
211
212 int main(int argc, char **argv)
213 {
214 int port, drive, track, ret = 0;
215 FILE *f;
216
217 // Parse arguments
218 if (argc != 4) {
219 fprintf(stderr, "Usage: %s <port> <drive> <file>\n", argv[0]);
220 return 1;
221 }
222
223 port = strtol(argv[1], NULL, 16);
224 drive = atoi(argv[2]) & 1;
225
226 // Open input file
227 f = fopen(argv[3], "rb");
228 if (f == NULL) {
229 fprintf(stderr, "Can't open %s for reading: %s\n", argv[3], strerror(errno));
230 return 1;
231 }
232
233 // Obtain access to I/O ports
234 if (ioperm(port, 8, 1) == -1) {
235 fprintf(stderr, "No access to I/O ports\n");
236 return 1;
237 }
238 setuid(getuid());
239
240 // Init Catweasel
241 memset(&c, 0, sizeof(c));
242 c.iobase = port;
243 c.msdelay = msdelay;
244 c.type = CATWEASEL_TYPE_MK1;
245 catweasel_init_controller(&c);
246
247 // Start drive
248 catweasel_select(&c, drive == 0, drive == 1);
249 catweasel_set_motor(c.drives + drive, 1);
250 msdelay(500);
251 catweasel_seek(c.drives + drive, 0);
252 msdelay(20);
253
254 // Disk write protected?
255 if (!catweasel_write_protected(c.drives + drive)) {
256
257 // No, write all tracks
258 for (track = 1; track <= NUM_TRACKS; track++) {
259 printf("Track %d...\n", track);
260 if (fread(track_buf, 256, num_sectors[track], f) != num_sectors[track]) {
261 fprintf(stderr, "Error reading input file\n");
262 break;
263 }
264 if (!write_track(drive, track))
265 break;
266 }
267
268 } else {
269
270 fprintf(stderr, "Error: disk write-protected\n");
271 ret = 1;
272 }
273
274 // Stop drive
275 catweasel_set_motor(c.drives + drive, 0);
276 catweasel_select(&c, 0, 0);
277 catweasel_free_controller(&c);
278
279 // Close input file
280 fclose(f);
281
282 return ret;
283 }