/* 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.
*
*/
struct device *newDevice(struct device *old, struct device *new) {
if (!old) {
if (!new) {
new = malloc(sizeof(struct device));
memset(new,'\0',sizeof(struct device));
}
new->class = CLASS_UNSPEC;
} else {
new->class = old->class;
if (old->device) new->device = strdup(old->device);
if (old->driver) new->driver = strdup(old->driver);
if (old->desc) new->desc = strdup(old->desc);
}
new->newDevice = newDevice;
new->freeDevice = freeDevice;
new->compareDevice = compareDevice;
return new;
}
void freeDevice(struct device *dev) {
if (!dev) {
printf("freeDevice(null)\n");
abort(); /* return; */
}
if (dev->device) free (dev->device);
if (dev->driver) free (dev->driver);
if (dev->desc) free (dev->desc);
free (dev);
}
void writeDevice(FILE *file, struct device *dev) {
int bus, i;
if (!file) {
printf("writeDevice(null,dev)\n");
abort();
}
if (!dev) {
printf("writeDevice(file,null)\n");
abort();
}
if (dev->bus == BUS_UNSPEC)
bus = 0;
else
for (bus = 1, i = dev->bus; !(i & 1); bus++, i>>=1);
fprintf(file,"-\nclass: %s\nbus: %s\ndetached: %d\n",
classStrings[dev->class],buses[bus].string,dev->detached);
if (dev->device)
fprintf(file,"device: %s\n",dev->device);
fprintf(file,"driver: %s\ndesc: \"%s\"\n",dev->driver,dev->desc);
}
int compareDevice(struct device *dev1, struct device *dev2) {
if (!dev1 || !dev2) return 1;
if (dev1->class != dev2->class) return 1;
if (dev1->bus != dev2->bus) return 1;
if (dev1->device && dev2->device && strcmp(dev1->device,dev2->device))
return 1;
/* Look - a special case!
* If it's just the driver that changed, we might
* want to act differently on upgrades.
*/
if (strcmp(dev1->driver,dev2->driver)) return 2;
return 0;
}
if (!file) {
printf("readDevice(null)\n");
abort();
}
memset(linebuf,'\0',512);
while (strcmp(linebuf,"-")) {
memset(linebuf,'\0',512);
linebuf=fgets(linebuf,512,file);
if (!linebuf) break;
/* kill trailing \n */
(*rindex(linebuf,'\n'))='\0';
if (!strcmp(linebuf,"-")) {
break;
} else {
if (!retdev) retdev = newDevice(NULL,NULL);
}
if (!strncmp(linebuf,"class:",6)) {
for (i=0;
classStrings[i] && strcmp(classStrings[i],linebuf+7);
i++);
if (classStrings[i])
retdev->class = i;
else
retdev->class = CLASS_OTHER;
} else if (!strncmp(linebuf,"bus:",4)) {
for (i=0;
buses[i].string && strcmp(buses[i].string,linebuf+5);
i++);
if (buses[i].string) {
tmpdev = (struct device *)buses[i].newFunc(retdev);
retdev->freeDevice(retdev);
retdev = tmpdev;
} else
retdev->bus = BUS_OTHER;
} else if (!strncmp(linebuf,"driver:",7)) {
retdev->driver = strdup(linebuf+8);
} else if (!strncmp(linebuf,"detached:",9)) {
retdev->detached = atoi(linebuf+10);
} else if (!strncmp(linebuf,"device:",7)) {
retdev->device = strdup(linebuf+8);
} else if (!strncmp(linebuf,"desc:",5)) {
if (rindex(linebuf,'"')!=index(linebuf,'"')) {
(*rindex(linebuf,'"')) = '\0';
retdev->desc = strdup(index(linebuf,'"')+1);
} else {
retdev->desc = strdup(linebuf+6);
}
}
switch (retdev->bus) {
case BUS_PCI:
if (!strncmp(linebuf,"vendorId:",9))
((struct pciDevice *)retdev)->vendorId = strtol(linebuf+10, (char **) NULL, 16);
else if (!strncmp(linebuf,"deviceId:",9))
((struct pciDevice *)retdev)->deviceId = strtol(linebuf+10, (char **) NULL, 16);
else if (!strncmp(linebuf,"pciType:",8))
((struct pciDevice *)retdev)->pciType = strtol(linebuf+6, (char **) NULL, 9);
break;
case BUS_PARALLEL:
if (!strncmp(linebuf,"pnpmodel:",9))
((struct parallelDevice *)retdev)->pnpmodel = strdup(linebuf+10);
if (!strncmp(linebuf,"pnpmfr:",7))
((struct parallelDevice *)retdev)->pnpmfr = strdup(linebuf+8);
if (!strncmp(linebuf,"pnpmodes:",9))
((struct parallelDevice *)retdev)->pnpmodes = strdup(linebuf+10);
if (!strncmp(linebuf,"pnpdesc:",8))
((struct parallelDevice *)retdev)->pnpdesc = strdup(linebuf+9);
if (!strncmp(linebuf,"pinfo.xres:",11))
((struct parallelDevice *)retdev)->pinfo->xres = atoi(linebuf+12);
if (!strncmp(linebuf,"pinfo.yres:",11))
((struct parallelDevice *)retdev)->pinfo->yres = atoi(linebuf+12);
if (!strncmp(linebuf,"pinfo.color:",12))
((struct parallelDevice *)retdev)->pinfo->color = atoi(linebuf+13);
if (!strncmp(linebuf,"pinfo.ascii:",12))
((struct parallelDevice *)retdev)->pinfo->ascii = atoi(linebuf+13);
if (!strncmp(linebuf,"pinfo.uniprint:",15))
((struct parallelDevice *)retdev)->pinfo->uniprint = strdup(linebuf+16);
break;
case BUS_SERIAL:
if (!strncmp(linebuf,"pnpmodel:",9))
((struct serialDevice *)retdev)->pnpmodel = strdup(linebuf+10);
if (!strncmp(linebuf,"pnpmfr:",7))
((struct serialDevice *)retdev)->pnpmfr = strdup(linebuf+8);
if (!strncmp(linebuf,"pnpcompat:",10))
((struct serialDevice *)retdev)->pnpcompat = strdup(linebuf+11);
if (!strncmp(linebuf,"pnpdesc:",8))
((struct serialDevice *)retdev)->pnpdesc = strdup(linebuf+9);
break;
case BUS_SBUS:
if (!strncmp(linebuf,"width:",6))
((struct sbusDevice *)retdev)->width = atoi(linebuf+7);
if (!strncmp(linebuf,"height:",7))
((struct sbusDevice *)retdev)->height = atoi(linebuf+8);
if (!strncmp(linebuf,"freq:",5))
((struct sbusDevice *)retdev)->freq = atoi(linebuf+6);
if (!strncmp(linebuf,"monitor:",8))
((struct sbusDevice *)retdev)->monitor = atoi(linebuf+9);
break;
case BUS_SCSI:
if (!strncmp(linebuf,"host:",5))
((struct scsiDevice *)retdev)->host = atoi(linebuf+6);
if (!strncmp(linebuf,"channel:",8))
((struct scsiDevice *)retdev)->channel = atoi(linebuf+9);
if (!strncmp(linebuf,"id:",3))
((struct scsiDevice *)retdev)->id = atoi(linebuf+4);
if (!strncmp(linebuf,"lun:",3))
((struct scsiDevice *)retdev)->lun = atoi(linebuf+4);
break;
case BUS_IDE:
if (!strncmp(linebuf,"physical:",9))
((struct ideDevice *)retdev)->physical = strdup(linebuf+10);
if (!strncmp(linebuf,"logical:",8))
((struct ideDevice *)retdev)->logical = strdup(linebuf+9);
break;
#ifdef _i_wanna_build_this_crap_
case BUS_ISAPNP:
if (!strncmp(linebuf,"pdeviceId:",10))
((struct isapnpDevice *)retdev)->pdeviceId = strdup(linebuf+11);
if (!strncmp(linebuf,"ppnpdesc:",9))
((struct isapnpDevice *)retdev)->ppnpdesc = strdup(linebuf+10);
if (!strncmp(linebuf,"deviceId:",9))
((struct isapnpDevice *)retdev)->deviceId = strdup(linebuf+10);
if (!strncmp(linebuf,"pnpdesc:",8))
((struct isapnpDevice *)retdev)->pnpdesc = strdup(linebuf+9);
if (!strncmp(linebuf,"compat:",7))
((struct isapnpDevice *)retdev)->compat = strdup(linebuf+8);
if (!strncmp(linebuf,"io:",3))
((struct isapnpDevice *)retdev)->io = isapnpReadResources(linebuf+4,16);
if (!strncmp(linebuf,"irq:",4))
((struct isapnpDevice *)retdev)->irq = isapnpReadResources(linebuf+5,10);
if (!strncmp(linebuf,"dma:",4))
((struct isapnpDevice *)retdev)->dma = isapnpReadResources(linebuf+5,10);
if (!strncmp(linebuf,"mem:",4))
((struct isapnpDevice *)retdev)->mem = isapnpReadResources(linebuf+5,16);
break;
#endif
default:
break;
}
}
return retdev;
}
#endif
int initializeDeviceList() {
int bus;
for (bus=0;buses[bus].string;bus++)
if (buses[bus].initFunc)
buses[bus].initFunc(NULL);
return 0;
}
void freeDeviceList() {
int bus;
for (bus=0;buses[bus].string;bus++)
if (buses[bus].freeFunc)
buses[bus].freeFunc();
}
/* used to sort device lists by a) type, b) device, c) description */
static int devCmp( const void *a, const void *b )
{
const struct device *one,*two;
int x,y,z,zz;
one=((const struct device **)a)[0];
two=((const struct device **)b)[0];
x=one->class - two->class;
if (one->device && two->device)
y=strcmp(one->device,two->device);
else {
y = one->device - two->device;
}
z=two->index - one->index;
zz=strcmp(one->desc,two->desc);
if (x)
return x;
else if (y)
return y;
else if (z)
return z;
else
return zz;
}