/* Copyright 1999 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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "ide.h"

static void ideFreeDevice(struct ideDevice *dev)
{
       if (dev->physical) free(dev->physical);
       if (dev->logical) free(dev->logical);
       freeDevice((struct device *) dev);
}

static void ideWriteDevice(FILE *file, struct ideDevice *dev)
{
       writeDevice(file, (struct device *)dev);
       if (dev->physical)
         fprintf(file,"physical: %s\n",
               dev->physical);
       if (dev->logical)
         fprintf(file,"logical: %s\n",
               dev->logical);

}

static int ideCompareDevice(struct ideDevice *dev1, struct ideDevice *dev2)
{
       return compareDevice((struct device *)dev1, (struct device *)dev2);
}

struct ideDevice *ideNewDevice(struct ideDevice *old)
{
       struct ideDevice *ret;

       ret = malloc(sizeof(struct ideDevice));
       memset(ret, '\0', sizeof(struct ideDevice));
       ret = (struct ideDevice *) newDevice((struct device *) old, (struct device *) ret);
       ret->bus = BUS_IDE;
       ret->newDevice = ideNewDevice;
       ret->freeDevice = ideFreeDevice;
       ret->writeDevice = ideWriteDevice;
       ret->compareDevice = ideCompareDevice;
       return ret;
}

struct device *ideProbe(enum deviceClass probeClass, int probeFlags,
                       struct device *devlist)
{
       DIR *dir;
       struct dirent *ent;
       char path[80];
       char readbuf[256];
       char *buf, *ptr;
       int fd, i;
       struct ideDevice *newdev;

       if (
           (probeClass == CLASS_UNSPEC) ||
           (probeClass == CLASS_OTHER) ||
           (probeClass == CLASS_CDROM) ||
           (probeClass == CLASS_FLOPPY) ||
           (probeClass == CLASS_TAPE) ||
           (probeClass == CLASS_HD)
           ) {
               if (access("/proc/ide", R_OK))
                       return devlist;

               if (!(dir = opendir("/proc/ide"))) {
                       return devlist;
               }
               while ((ent = readdir(dir))) {
                       sprintf(path, "/proc/ide/%s/media", ent->d_name);
                       if ((fd = open(path, O_RDONLY)) >= 0) {
                               i = read(fd, path, 50);
                               close(fd);
                               path[i - 1] = '\0';     /* chop off trailing \n */

                               newdev = ideNewDevice(NULL);
                               if (!strcmp(path, "cdrom"))
                                       newdev->class = CLASS_CDROM;
                               else if (!strcmp(path, "disk"))
                                       newdev->class = CLASS_HD;
                               else if (!strcmp(path, "tape"))
                                       newdev->class = CLASS_TAPE;
                               else if (!strcmp(path, "floppy"))
                                       newdev->class = CLASS_FLOPPY;
                               else
                                       newdev->class = CLASS_OTHER;
                               newdev->device = strdup(ent->d_name);
                               newdev->driver = strdup("ignore");

                               sprintf(path, "/proc/ide/%s/model", ent->d_name);
                               if ((fd = open(path, O_RDONLY)) >= 0) {
                                       i = read(fd, path, 50);
                                       close(fd);
                                       path[i - 1] = '\0';     /* chop off trailing \n */
                                       newdev->desc = strdup(path);
                               } else {
                                       newdev->desc = strdup("Generic IDE device");
                               }
                               sprintf(path,"/proc/ide/%s/geometry", ent->d_name);
                               if ((fd = open(path, O_RDONLY)) >= 0) {

                                       i  = read(fd, readbuf, 255);
                                       close(fd);
                                       buf=alloca(255);
                                       strncpy(buf,readbuf,254);
                                       ptr=buf;
                                       while(*buf) {
                                               while (*buf && (*buf != '\n')) buf++;
                                               if (*buf == '\n') {
                                                       *buf = '\0';
                                                       buf++;
                                               }
                                               if (!strncmp(ptr,"physical",8))
                                                 newdev->physical=strdup(ptr+13);
                                               if (!strncmp(ptr,"logical",7))
                                                 newdev->logical=strdup(ptr+13);
                                               ptr=buf;
                                       }
                               }
                               if (newdev->class == probeClass || probeClass == CLASS_UNSPEC) {
                                       if (devlist)
                                               newdev->next = devlist;
                                       devlist = (struct device *) newdev;
                               } else {
                                       newdev->freeDevice(newdev);
                               }
                       }
                       errno = 0;
               }
               closedir(dir);
       }
       return devlist;
}