/* Copyright 1999, 2000 Red Hat, Inc.
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fd.h>

#include "misc.h"

static void miscFreeDevice(struct miscDevice *dev)
{
	freeDevice((struct device *) dev);
}

static void miscWriteDevice(FILE *file, struct miscDevice *dev)
{
	writeDevice(file, (struct device *)dev);
}

static int miscCompareDevice(struct miscDevice *dev1, struct miscDevice *dev2)
{
	return compareDevice( (struct device *)dev1, (struct device *)dev2);
}

struct miscDevice *miscNewDevice(struct miscDevice *old)
{
	struct miscDevice *ret;

	ret = malloc(sizeof(struct miscDevice));
	memset(ret, '\0', sizeof(struct miscDevice));
	ret = (struct miscDevice *) newDevice((struct device *) old, (struct device *) ret);
	ret->bus = BUS_MISC;
	ret->newDevice = miscNewDevice;
	ret->freeDevice = miscFreeDevice;
	ret->writeDevice = miscWriteDevice;
	ret->compareDevice = miscCompareDevice;
	return ret;
}

static char *getFloppyDesc(char *name) {
	int size;
	char *type;
	char desc[64];
	
	size = atoi(name+1);
	
	if (isupper(name[0]))
	  type = "3.5\"";
	else
	  type = "5.25\"";
	if (size > 1000)
	  snprintf(desc, 63, "%s %d.%dMB floppy drive", type, size / 1000, (size % 1000) / 10);
	else 
	  snprintf(desc, 64, "%s %dKB floppy drive", type, size);
	return strdup(desc);
}

struct device *miscProbe(enum deviceClass probeClass, int probeFlags,
			struct device *devlist)
{
	int fd, x, rc;
	char path[32], name[32];
	struct miscDevice *miscdev;
	struct floppy_drive_struct ds;
	
	if (
	    (probeClass == CLASS_UNSPEC) ||
	    (probeClass == CLASS_FLOPPY) 
	    ) {
		for (x=0; x<=3; x++) {
			snprintf(path, 31, "/dev/fd%d", x);
			fd = open(path, O_RDONLY|O_NONBLOCK);
			if (fd < 0)
			  goto cont;
			ioctl(fd, FDRESET, NULL);
			rc = ioctl(fd, FDGETDRVTYP, name);
			if (rc || !name || !strcmp(name, "(null)"))
			  goto cont;
			rc = ioctl(fd, FDPOLLDRVSTAT, &ds);
			if (rc)
			  goto cont;
			miscdev = miscNewDevice(NULL);
			miscdev->device = strdup(basename(path));
			miscdev->class = CLASS_FLOPPY;
			miscdev->desc = getFloppyDesc(name);
			miscdev->driver = strdup("unknown");
			if (ds.track < 0)
			  miscdev->detached = 1;
			if (devlist)
			  miscdev->next = devlist;
			devlist = (struct device *) miscdev;
cont:
			close(fd);
		}
	}
	return devlist;
}
