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