--- sys/dev/pci/pci_user.c.orig 2009-09-19 16:13:10.000000000 +0800 +++ sys/dev/pci/pci_user.c 2012-02-04 01:52:50.000000000 +0700 @@ -225,6 +225,49 @@ u_int32_t pi_data; /* data to write or result of read */ }; +#ifdef COMPAT_FREEBSD32 +struct pci_conf_old32 { + struct pcisel_old pc_sel; /* bus+slot+function */ + u_int8_t pc_hdr; /* PCI header type */ + u_int16_t pc_subvendor; /* card vendor ID */ + u_int16_t pc_subdevice; /* card device ID, assigned by + card vendor */ + u_int16_t pc_vendor; /* chip vendor ID */ + u_int16_t pc_device; /* chip device ID, assigned by + chip vendor */ + u_int8_t pc_class; /* chip PCI class */ + u_int8_t pc_subclass; /* chip PCI subclass */ + u_int8_t pc_progif; /* chip PCI programming interface */ + u_int8_t pc_revid; /* chip revision ID */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* device unit number (u_long) */ +}; + +struct pci_match_conf_old32 { + struct pcisel_old pc_sel; /* bus+slot+function */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* Unit number (u_long) */ + u_int16_t pc_vendor; /* PCI Vendor ID */ + u_int16_t pc_device; /* PCI Device ID */ + u_int8_t pc_class; /* PCI class */ + pci_getconf_flags_old flags; /* Matching expression */ +}; + +struct pci_conf_io32 { + u_int32_t pat_buf_len; /* pattern buffer length */ + u_int32_t num_patterns; /* number of patterns */ + u_int32_t patterns; /* pattern buffer (struct pci_match_conf_old32 *) */ + u_int32_t match_buf_len; /* match buffer length */ + u_int32_t num_matches; /* number of matches returned */ + u_int32_t matches; /* match buffer (struct pci_conf_old32 *) */ + u_int32_t offset; /* offset into device list */ + u_int32_t generation; /* device list generation */ + pci_getconf_status status; /* request status */ +}; + +#define PCIOCGETCONF_OLD32 _IOWR('p', 1, struct pci_conf_io32) +#endif + #define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io) #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old) #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old) @@ -295,6 +338,69 @@ return(1); } +static int +pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches, + struct pci_conf *match_buf) +{ + int i; + + if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) + return(1); + + for (i = 0; i < num_matches; i++) { + if (match_buf->pc_sel.pc_domain != 0) + continue; + + /* + * I'm not sure why someone would do this...but... + */ + if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD) + continue; + + /* + * Look at each of the match flags. If it's set, do the + * comparison. If the comparison fails, we don't have a + * match, go on to the next item if there is one. + */ + if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) + && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) + && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) + && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) + && (match_buf->pc_vendor != matches[i].pc_vendor)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) + && (match_buf->pc_device != matches[i].pc_device)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) + && (match_buf->pc_class != matches[i].pc_class)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) + && ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) + && (strncmp(matches[i].pd_name, match_buf->pd_name, + sizeof(match_buf->pd_name)) != 0)) + continue; + + return(0); + } + + return(1); +} + #endif static int @@ -314,13 +420,21 @@ size_t confsz, iolen, pbufsz; int error, ionum, i, num_patterns; #ifdef PRE7_COMPAT +#ifdef COMPAT_FREEBSD32 + struct pci_conf_io32 *cio32; +#endif struct pci_conf_old conf_old; + struct pci_conf_old32 conf_old32; struct pci_io iodata; struct pci_io_old *io_old; struct pci_match_conf_old *pattern_buf_old; + struct pci_match_conf_old32 *pattern_buf_old32; + cio = NULL; + cio32 = NULL; io_old = NULL; pattern_buf_old = NULL; + pattern_buf_old32 = NULL; if (!(flag & FWRITE) && cmd != PCIOCGETBAR && cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD) @@ -332,11 +446,27 @@ switch(cmd) { #ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD32: + cio32 = (struct pci_conf_io32 *)data; + cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK); + cio->pat_buf_len = cio32->pat_buf_len; + cio->num_patterns = cio32->num_patterns; + cio->patterns = (void *)(uintptr_t)cio32->patterns; + cio->match_buf_len = cio32->match_buf_len; + cio->num_matches = cio32->num_matches; + cio->matches = (void *)(uintptr_t)cio32->matches; + cio->offset = cio32->offset; + cio->generation = cio32->generation; + cio->status = cio32->status; + cio32->num_matches = 0; + /* FALLTHROUGH */ + case PCIOCGETCONF_OLD: /* FALLTHROUGH */ #endif case PCIOCGETCONF: - cio = (struct pci_conf_io *)data; + if (cio == NULL) + cio = (struct pci_conf_io *)data; pattern_buf = NULL; num_patterns = 0; @@ -354,7 +484,7 @@ && (cio->generation != pci_generation)){ cio->status = PCI_GETCONF_LIST_CHANGED; error = 0; - break; + goto getconfexit; } /* @@ -364,7 +494,7 @@ if (cio->offset >= pci_numdevs) { cio->status = PCI_GETCONF_LAST_DEVICE; error = 0; - break; + goto getconfexit; } /* get the head of the device queue */ @@ -377,6 +507,11 @@ * didn't specify a multiple of that size. */ #ifdef PRE7_COMPAT +#ifdef COMPAT_FREEBSD32 + if (cmd == PCIOCGETCONF_OLD32) + confsz = sizeof(struct pci_conf_old32); + else +#endif if (cmd == PCIOCGETCONF_OLD) confsz = sizeof(struct pci_conf_old); else @@ -411,6 +546,11 @@ * updated their kernel but not their userland. */ #ifdef PRE7_COMPAT +#ifdef COMPAT_FREEBSD32 + if (cmd == PCIOCGETCONF_OLD32) + pbufsz = sizeof(struct pci_match_conf_old32); + else +#endif if (cmd == PCIOCGETCONF_OLD) pbufsz = sizeof(struct pci_match_conf_old); else @@ -420,13 +560,19 @@ /* The user made a mistake, return an error. */ cio->status = PCI_GETCONF_ERROR; error = EINVAL; - break; + goto getconfexit; } /* * Allocate a buffer to hold the patterns. */ #ifdef PRE7_COMPAT + if (cmd == PCIOCGETCONF_OLD32) { + pattern_buf_old32 = malloc(cio->pat_buf_len, + M_TEMP, M_WAITOK); + error = copyin(cio->patterns, + pattern_buf_old32, cio->pat_buf_len); + } else if (cmd == PCIOCGETCONF_OLD) { pattern_buf_old = malloc(cio->pat_buf_len, M_TEMP, M_WAITOK); @@ -452,7 +598,7 @@ */ cio->status = PCI_GETCONF_ERROR; error = EINVAL; - break; + goto getconfexit; } /* @@ -484,7 +630,11 @@ } #ifdef PRE7_COMPAT - if ((cmd == PCIOCGETCONF_OLD && + if ((cmd == PCIOCGETCONF_OLD32 && + (pattern_buf_old32 == NULL || + pci_conf_match_old32(pattern_buf_old32, + num_patterns, &dinfo->conf) == 0)) || + (cmd == PCIOCGETCONF_OLD && (pattern_buf_old == NULL || pci_conf_match_old(pattern_buf_old, num_patterns, &dinfo->conf) == 0)) || @@ -509,6 +659,38 @@ break; #ifdef PRE7_COMPAT + if (cmd == PCIOCGETCONF_OLD32) { + conf_old32.pc_sel.pc_bus = + dinfo->conf.pc_sel.pc_bus; + conf_old32.pc_sel.pc_dev = + dinfo->conf.pc_sel.pc_dev; + conf_old32.pc_sel.pc_func = + dinfo->conf.pc_sel.pc_func; + conf_old32.pc_hdr = dinfo->conf.pc_hdr; + conf_old32.pc_subvendor = + dinfo->conf.pc_subvendor; + conf_old32.pc_subdevice = + dinfo->conf.pc_subdevice; + conf_old32.pc_vendor = + dinfo->conf.pc_vendor; + conf_old32.pc_device = + dinfo->conf.pc_device; + conf_old32.pc_class = + dinfo->conf.pc_class; + conf_old32.pc_subclass = + dinfo->conf.pc_subclass; + conf_old32.pc_progif = + dinfo->conf.pc_progif; + conf_old32.pc_revid = + dinfo->conf.pc_revid; + strncpy(conf_old32.pd_name, + dinfo->conf.pd_name, + sizeof(conf_old32.pd_name)); + conf_old32.pd_name[PCI_MAXNAMELEN] = 0; + conf_old32.pd_unit = + (u_int32_t)dinfo->conf.pd_unit; + confdata = &conf_old32; + } else if (cmd == PCIOCGETCONF_OLD) { conf_old.pc_sel.pc_bus = dinfo->conf.pc_sel.pc_bus; @@ -575,9 +757,22 @@ cio->status = PCI_GETCONF_MORE_DEVS; getconfexit: +#ifdef COMPAT_FREEBSD32 + if (cmd == PCIOCGETCONF_OLD32) { + cio32->status = cio->status; + cio32->generation = cio->generation; + cio32->offset = cio->offset; + cio32->num_matches = cio->num_matches; + if (cio != NULL) + free(cio, M_TEMP); + } +#endif + if (pattern_buf != NULL) free(pattern_buf, M_TEMP); #ifdef PRE7_COMPAT + if (pattern_buf_old32 != NULL) + free(pattern_buf_old32, M_TEMP); if (pattern_buf_old != NULL) free(pattern_buf_old, M_TEMP); #endif