1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * ami-disk.c: Creates pseudo dev: handler. Copy tracks to rawfile
5 * (used in zfile.c).
6 *
7 * 08/06/97: Modified to avoid a spilled registers error message
8 * when used with the new fd2inline convention.
9 *
10 * Copyright 1996 Samuel Devulder.
11 */
12
13 #include "sysconfig.h"
14 #include "sysdeps.h"
15
16 /****************************************************************************/
17
18 #include <exec/execbase.h>
19 #include <exec/memory_uae.h>
20 #include <exec/devices.h>
21 #include <exec/io.h>
22
23 #include <dos/dos.h>
24
25 #include <devices/trackdisk.h>
26
27 #if defined(POWERUP)
28 #include <dos/dosextens.h>
29 #ifdef USE_CLIB
30 #include <clib/exec_protos.h>
31 #include <clib/alib_protos.h>
32 #else
33 #include <powerup/ppcproto/exec.h>
34 #include <powerup/ppcproto/dos.h>
35 #endif
36 #else
37 /* This should cure the spilled-register problem. An other solution is to */
38 /* compile with -O2 instead of -O3 */
39 #define NO_INLINE_STDARGS
40 #define __NOINLINES__
41
42 #include <proto/exec.h>
43 #ifndef __SASC
44 #include <clib/alib_protos.h>
45 #endif
46 #include <proto/dos.h>
47 #endif
48
49 /****************************************************************************/
50
51 #include <ctype.h>
52 #include <signal.h>
53
54 /****************************************************************************/
55
56 const char *amiga_dev_path = "DEV:";
57 const char *ixemul_dev_path = "/dev/";
58
59 int readdevice (char *name, char *dst);
60 void initpseudodevices (void);
61 void closepseudodevices (void);
62
63 static void myDoIO(struct IOStdReq *ioreq, LONG CMD, LONG FLAGS, LONG OFFSET,
64 LONG LENGTH, LONG DATA);
65
66 /****************************************************************************/
67
68 static const char *pseudo_dev_path = "T:DEV";
69
70 static char pseudo_dev_created = 0;
71 static char pseudo_dev_assigned = 0;
72 static char dfx_done[4];
73
74 static int device_exists (const char *device_name, int device_unit);
75 static int dev_inhibit(char *dev,int on);
76 static void set_req(int ok);
77
78 /****************************************************************************/
79 /*
80 * Creates peudo DEV:DFx files.
81 */
initpseudodevices(void)82 void initpseudodevices(void)
83 {
84 ULONG lock;
85 int i;
86
87 pseudo_dev_created = 0;
88 pseudo_dev_assigned = 0;
89 for(i=0;i<4;++i) dfx_done[i]=0;
90
91 /* check if dev: already exists */
92 set_req(0);lock = Lock(amiga_dev_path,SHARED_LOCK);set_req(1);
93 if(!lock) {
94 char name[80];
95 set_req(0);lock = Lock(pseudo_dev_path,SHARED_LOCK);set_req(1);
96 if(!lock) {
97 /* create it */
98 lock = CreateDir(pseudo_dev_path);
99 if(!lock) goto fail;
100 UnLock(lock);lock = Lock(pseudo_dev_path,SHARED_LOCK);
101 pseudo_dev_created = 1;
102 }
103 strcpy(name,amiga_dev_path);
104 if(*name && name[strlen(name)-1]==':') name[strlen(name)-1]='\0';
105 if(!AssignLock(name,lock)) {UnLock(lock);goto fail;}
106 /* the lock is the assign now */
107 pseudo_dev_assigned = 1;
108 } else UnLock(lock);
109
110 /* Create the dev:DFi entry */
111 for(i=0;i<4;++i) if(device_exists("trackdisk.device",i)) {
112 ULONG fd;
113 char name[80];
114
115 sprintf(name,"%sDF%d",amiga_dev_path,i);
116 fd = Open(name,MODE_NEWFILE);
117 if(fd) {Close(fd);dfx_done[i]=1;}
118 }
119
120 return;
121 fail:
122 fprintf(stderr,"Failed to create pseudo dev: entry!\n");
123 }
124
125 /****************************************************************************/
126 /*
127 * Cleanup pseudo DEV:DFx
128 */
closepseudodevices(void)129 void closepseudodevices(void)
130 {
131 int i;
132 for(i=0;i<4;++i) if(dfx_done[i]) {
133 char name[80];
134 sprintf(name,"%sDF%d",amiga_dev_path,i);
135 DeleteFile(name);
136 dfx_done[i] = 0;
137 }
138
139 if(pseudo_dev_assigned) {
140 char name[80];
141 strcpy(name,amiga_dev_path);
142 if(*name && name[strlen(name)-1]==':') name[strlen(name)-1]='\0';
143 AssignLock (name, (BPTR)NULL);
144 pseudo_dev_assigned = 0;
145 }
146
147 if(pseudo_dev_created) {
148 DeleteFile(pseudo_dev_path);
149 pseudo_dev_created = 0;
150 }
151 }
152
153 /****************************************************************************/
154 /*
155 * Enable/Disable system requester
156 */
set_req(int ok)157 static void set_req(int ok)
158 {
159 static ULONG wd = 0;
160 struct Process *pr;
161
162 pr = (void*)FindTask(NULL);
163
164 if(pr->pr_Task.tc_Node.ln_Type != NT_PROCESS) return;
165
166 if(ok) {
167 pr->pr_WindowPtr = (APTR)wd;
168 }
169 else {
170 wd = (ULONG)pr->pr_WindowPtr;
171 pr->pr_WindowPtr = (APTR)-1;
172 }
173 }
174
175 /****************************************************************************/
176 /*
177 * checks if a device exists
178 */
device_exists(const char * device_name,int device_unit)179 static int device_exists (const char *device_name, int device_unit)
180 {
181 struct IOStdReq *ioreq = NULL;
182 struct MsgPort *port = NULL;
183 int ret = 0;
184
185 port = CreatePort(0, 0);
186 if(port) {
187 ioreq = CreateStdIO(port);
188 if(ioreq) {
189 if(!OpenDevice(device_name,device_unit,(void*)ioreq,0)) {
190 CloseDevice((void*)ioreq);
191 ret = 1;
192 }
193 DeleteStdIO(ioreq);
194 }
195 DeletePort(port);
196 }
197 return ret;
198 }
199
200 /****************************************************************************/
201 /*
202 * extract the device and unit form a filename.
203 */
extract_dev_unit(char * name,char ** dev_name,int * dev_unit)204 static void extract_dev_unit(char *name, char **dev_name, int *dev_unit)
205 {
206 char *s;
207 if(tolower(name[0])=='d' && tolower(name[1])=='f' &&
208 name[2]>='0' && name[2]<='3' && name[3]=='\0') {
209 /* DF0 */
210 *dev_unit = name[2]-'0';
211 *dev_name = strdup("trackdisk.device");
212 } else if((s = strrchr(name,'/'))) {
213 /* trackdisk[.device]/0 */
214 *dev_unit = atoi(s+1);
215 *dev_name = malloc(1 + s-name);
216 if(*dev_name) {
217 strncpy(*dev_name, name, 1 + s-name);
218 (*dev_name)[s-name]='\0';
219 }
220 } else {
221 /* ?? STRANGEDISK0: ?? */
222 *dev_unit = 0;
223 *dev_name = strdup(name);
224 }
225 if(*dev_name) {
226 char *s;
227 if(!(s = strrchr(*dev_name,'.'))) {
228 /* .device is missing */
229 s = malloc(8+strlen(*dev_name));
230 if(s) {
231 sprintf(s,"%s.device",*dev_name);
232 xfree(*dev_name);
233 *dev_name = s;
234 }
235 }
236 }
237 }
238
239 /****************************************************************************/
240 /*
241 * copy a device to a FILE*.
242 */
raw_copy(char * dev_name,int dev_unit,FILE * dst)243 static int raw_copy(char *dev_name, int dev_unit, FILE *dst)
244 {
245 struct MsgPort *port = NULL;
246 struct IOStdReq *ioreq = NULL;
247 int tracklen = 512*11;
248 int retstatus = 1;
249 int inhibited = 0;
250 char *buffer = NULL;
251 static char name[] = {'D','F','0','\0'};
252
253 if(!strcmp(dev_name, "trackdisk.device")) {
254 inhibited = 1;
255 name[2] = '0'+dev_unit;
256 }
257
258 /* allocate system stuff */
259 if((port = CreatePort(0, 0))) {
260 if((ioreq = CreateStdIO(port))) {
261 if((buffer = AllocMem(tracklen, MEMF_CHIP))) {
262
263 /* gain access to the device */
264 if(!OpenDevice(dev_name, dev_unit, (struct IORequest*)ioreq, 0)) {
265
266 /* check if a disk is present */
267 myDoIO(ioreq, TD_CHANGESTATE, 0, -1, -1, -1);
268 if(!ioreq->io_Error && ioreq->io_Actual) {
269 fprintf(stderr,"No disk in %s unit %d !\n", dev_name, dev_unit);
270 retstatus = 0;
271 } else {
272 int tr = 0;
273 int write_protected = 0;
274 /* check if disk is write-protected:
275 myDoIO(ioreq, TD_PROTSTATUS, 0, -1, -1, -1);
276 if(!ioreq->io_Error && ioreq->io_Actual) write_protected = 1;
277 */
278
279 /* inhibit device */
280 if(inhibited) inhibited = dev_inhibit(name,1);
281
282 /* read tracks */
283 for(tr = 0; tr < 160; ++tr) {
284 printf("Reading track %2d side %d of %s unit %d \r",
285 tr/2, tr%2, dev_name, dev_unit);
286 fflush(stdout);
287 myDoIO(ioreq, CMD_READ, -1, tracklen*tr, tracklen, (LONG)buffer);
288 if(ioreq->io_Error) printf("Err. on\n");
289 if(fwrite(buffer, 1, tracklen, dst) != (unsigned int)tracklen) {
290 retstatus = 0;
291 break;
292 }
293 }
294
295 /* ok everything done! */
296 printf(" \r");
297 fflush(stdout);
298
299 /* stop motor */
300 myDoIO(ioreq, TD_MOTOR, 0, -1, 0, -1);
301
302 /* uninhibit */
303 if(inhibited) dev_inhibit(name,0);
304 }
305 CloseDevice((struct IORequest*)ioreq); } else retstatus = 0;
306 FreeMem(buffer,tracklen); } else retstatus = 0;
307 DeleteStdIO(ioreq); } else retstatus = 0;
308 DeletePort(port); } else retstatus = 0;
309 return retstatus;
310 }
311
312 /****************************************************************************/
313 /*
314 * Copy one raw disk to a file.
315 */
readdevice(char * name,char * dst)316 int readdevice(char *name, char *dst)
317 { /* erhm, I must admit this code is long and ugly! */
318 FILE *f = NULL;
319 char *device_name;
320 int device_unit;
321 int retstatus = 0;
322 #ifdef HAVE_SIGACTION
323 struct sigaction oldsa;
324 int oldsa_valid;
325
326 /* disable break */
327 oldsa_valid = (0==sigaction(SIGINT, NULL, &oldsa));
328 signal(SIGINT, SIG_IGN); /* <--- gcc complains about something */
329 /* in there but I don't know why. */
330 #endif
331
332 /* get device name & unit */
333 extract_dev_unit(name, &device_name, &device_unit);
334 if(device_name) {
335 /* if no destination then just check if the device exists */
336 if(dst == NULL)
337 retstatus = device_exists(device_name, device_unit);
338 else {
339 /* open dest file */
340 if((f = fopen(dst,"wb"))) {
341 retstatus = raw_copy(device_name, device_unit, f);
342 fclose(f);
343 }
344 }
345 xfree(device_name);
346 }
347
348 #ifdef HAVE_SIGACTION
349 /* enable break */
350 if(oldsa_valid) sigaction(SIGINT, &oldsa, NULL);
351 #endif
352
353 return retstatus;
354 }
355
356 /****************************************************************************/
357
myDoIO(struct IOStdReq * ioreq,LONG CMD,LONG FLAGS,LONG OFFSET,LONG LENGTH,LONG DATA)358 static void myDoIO(struct IOStdReq *ioreq, LONG CMD, LONG FLAGS, LONG OFFSET,
359 LONG LENGTH, LONG DATA)
360 {
361 if(CMD>=0) ioreq->io_Command = CMD;
362 if(FLAGS>=0) ioreq->io_Flags = FLAGS;
363 if(OFFSET>=0) ioreq->io_Offset = OFFSET;
364 if(LENGTH>=0) ioreq->io_Length = LENGTH;
365 if(DATA>=0) ioreq->io_Data = (void*)DATA;
366 DoIO((struct IORequest*)ioreq);
367 }
368
369 /****************************************************************************/
370 /*
371 * Prevents DOS to access a DFx device.
372 */
dev_inhibit(char * dev,int on)373 static int dev_inhibit (char *dev, int on)
374 {
375 char buff[10];
376 char *s;
377 struct MsgPort *DevPort;
378
379 if (!*dev)
380 return 0;
381
382 s = dev;
383 while(*s++);
384
385 if (s[-2] == ':')
386 strcpy (buff, dev);
387 else
388 sprintf (buff, "%s:", dev);
389
390 if ((DevPort = (struct MsgPort*) DeviceProc ((STRPTR)buff))) {
391 if (on) {
392 DoPkt (DevPort, ACTION_INHIBIT, DOSTRUE, 0, 0, 0, 0);
393 return 1;
394 }
395 else
396 DoPkt (DevPort, ACTION_INHIBIT, DOSFALSE, 0, 0, 0, 0);
397 }
398 return 0;
399 }
400