1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <unistd.h>
21
22 #include "kc/system.h"
23
24 #include "kc/kc.h"
25 #include "kc/fdc.h"
26 #include "kc/disk.h"
27 #include "kc/floppy.h"
28
29 #include "cmd/cmd.h"
30
31 #include "sys/sysdep.h"
32
33 #include "ui/status.h"
34
35 #include "libdbg/dbg.h"
36
37 class CMD_disk_attach : public CMD
38 {
39 private:
40 Disk *_d;
41 static const char * _path;
42
43 protected:
get_disk_no(CMD_Args * args)44 int get_disk_no(CMD_Args *args)
45 {
46 int n = 0;
47
48 if (args && args->has_arg("disk"))
49 n = args->get_long_arg("disk");
50
51 return n;
52 }
53
54 public:
CMD_disk_attach(Disk * d)55 CMD_disk_attach(Disk *d) : CMD("disk-attach")
56 {
57 _d = d;
58 register_cmd("disk-attach", 0);
59 register_cmd("disk-detach", 3);
60 }
61
execute(CMD_Args * args,CMD_Context context)62 void execute(CMD_Args *args, CMD_Context context)
63 {
64 bool create;
65 char buf[1000];
66 disk_error_t err;
67 char *shortname;
68 const char *filename;
69
70 create = false;
71 filename = NULL;
72 switch (context)
73 {
74 /*
75 * disk-attach
76 */
77 case 0:
78 if (!args)
79 args = new CMD_Args();
80 filename = args->get_string_arg("filename");
81 if (!filename)
82 {
83 args->set_string_arg("ui-file-select-title",
84 _("Select disk..."));
85 if (_path)
86 args->set_string_arg("ui-file-select-path", _path);
87 args->add_callback("ui-file-select-CB-ok", this, 1);
88 CMD_EXEC_ARGS("ui-file-select", args);
89 return;
90 }
91 break;
92 /*
93 * ui-file-select-CB-ok
94 */
95 case 1:
96 if (args)
97 filename = args->get_string_arg("filename");
98 break;
99 /*
100 * ui-dialog-yes-no-CB-yes
101 */
102 case 2:
103 if (args)
104 filename = args->get_string_arg("filename");
105 create = true;
106 break;
107 /*
108 * disk-detach
109 */
110 case 3:
111 _d->detach(get_disk_no(args));
112 return;
113 }
114
115 if (filename)
116 {
117 _path = filename;
118 err = _d->attach(get_disk_no(args), filename, create);
119 switch (err)
120 {
121 case DISK_NOENT:
122 if (!create)
123 {
124 args->set_string_arg("ui-dialog-title", _("create file?"));
125 args->set_string_arg("ui-dialog-text",
126 _("The file '%s' doesn't exist.\n"
127 "Do you want to create it?"));
128 args->set_string_arg("ui-dialog-text-arg", "filename");
129 args->add_callback("ui-dialog-yes-no-CB-yes", this, 2);
130 CMD_EXEC_ARGS("ui-dialog-yes-no", args);
131 }
132 break;
133 case DISK_OK:
134 shortname = sys_basename(filename);
135 snprintf(buf, sizeof(buf), _("disk-file `%s' attached."), shortname);
136 free(shortname);
137 Status::instance()->setMessage(buf);
138 break;
139 default:
140 Status::instance()->setMessage(_("Can't attach disk-file."));
141 break;
142 }
143 }
144 }
145 };
146
147 const char * CMD_disk_attach::_path = NULL;
148
Disk()149 Disk::Disk()
150 {
151 _cmd = new CMD_disk_attach(this);
152 }
153
~Disk()154 Disk::~Disk()
155 {
156 delete _cmd;
157 }
158
159 bool
create_disk_file(FILE * f)160 Disk::create_disk_file(FILE *f)
161 {
162 for (int c = 0;c < 80;c++)
163 for (int h = 0;h < 2;h++)
164 for (int s = 1;s < 6;s++)
165 if (!write_sector(f, c, h, s))
166 return false;
167
168 return true;
169 }
170
171 bool
write_sector(FILE * f,int c,int h,int s)172 Disk::write_sector(FILE *f, int c, int h, int s)
173 {
174 if (fputc(c, f) == EOF) // acyl
175 return false;
176 if (fputc(h, f) == EOF) // asid
177 return false;
178 if (fputc(c, f) == EOF) // lcyl
179 return false;
180 if (fputc(h, f) == EOF) // lsid
181 return false;
182 if (fputc(s, f) == EOF) // lsec
183 return false;
184 if (fputc(3, f) == EOF) // llen
185 return false;
186 if (fputc(0, f) == EOF) // count low
187 return false;
188 if (fputc(4, f) == EOF) // count high
189 return false;
190
191 for (int a = 0;a < 1024;a++)
192 if (fputc(0xe5, f) == EOF)
193 return false;
194
195 return true;
196 }
197
198 disk_error_t
attach(int disk_no,const char * filename,bool create)199 Disk::attach(int disk_no, const char *filename, bool create)
200 {
201 char *ptr;
202 disk_error_t ret;
203
204 if (fdc_fdc == NULL)
205 return DISK_ERROR;
206
207 if (filename == NULL)
208 return DISK_ERROR;
209
210 ret = DISK_OK;
211
212 if (create)
213 {
214 DBG(1, form("KCemu/Disk/attach",
215 "Disk::attach(): [disk %d] create (%s)\n",
216 disk_no, filename));
217
218 FILE *f = fopen(filename, "wb");
219 if (f == NULL)
220 return DISK_ERROR;
221
222 bool create_ok = create_disk_file(f);
223 fclose(f);
224
225 if (!create_ok)
226 return DISK_ERROR;
227 }
228
229 DBG(1, form("KCemu/Disk/attach",
230 "Disk::attach(): [disk %d] open (%s)\n",
231 disk_no, filename));
232
233 Floppy *floppy = fdc_fdc->get_floppy(disk_no);
234 if (floppy != NULL)
235 {
236 if (access(filename, R_OK) == 0)
237 {
238 ptr = strdup(filename);
239 }
240 else
241 {
242 ptr = (char *)malloc(strlen(kcemu_datadir) + strlen(filename) + 11);
243 strcpy(ptr, kcemu_datadir);
244 strcat(ptr, "/disks/");
245 strcat(ptr, filename);
246 if (access(ptr, R_OK) != 0)
247 strcat(ptr, ".gz");
248 }
249
250 if (access(ptr, R_OK) == 0)
251 {
252 if (!floppy->attach(ptr))
253 ret = DISK_ERROR;
254 }
255 else
256 {
257 ret = DISK_NOENT;
258 }
259
260 free(ptr);
261 }
262
263 CMD_Args *args = new CMD_Args();
264 args->set_long_arg("disk", disk_no);
265 args->set_string_arg("filename", filename);
266 CMD_EXEC_ARGS("ui-disk-update-MSG", args);
267 delete args;
268
269 return ret;
270 }
271
272 disk_error_t
detach(int disk_no)273 Disk::detach(int disk_no)
274 {
275 if (fdc_fdc == NULL)
276 return DISK_ERROR;
277
278 DBG(1, form("KCemu/Disk/detach",
279 "Disk::detach(): [disk %d] close\n",
280 disk_no));
281
282 Floppy *floppy = fdc_fdc->get_floppy(disk_no);
283 if (floppy != NULL)
284 floppy->attach(NULL);
285
286 CMD_Args *args = new CMD_Args();
287 args->set_long_arg("disk", disk_no);
288 args->set_string_arg("filename", "");
289 CMD_EXEC_ARGS("ui-disk-update-MSG", args);
290 delete args;
291
292 return DISK_OK;
293 }
294