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, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.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     }