From owner-svn-src-user@FreeBSD.ORG Mon May 10 16:35:14 2010 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 4BB9C1065676; Mon, 10 May 2010 16:35:14 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [69.147.83.44]) by mx1.freebsd.org (Postfix) with ESMTP id 3B14A8FC2E; Mon, 10 May 2010 16:35:14 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o4AGZE7O006532; Mon, 10 May 2010 16:35:14 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o4AGZDXl006531; Mon, 10 May 2010 16:35:13 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <201005101635.o4AGZDXl006531@svn.freebsd.org> From: Warner Losh Date: Mon, 10 May 2010 16:35:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r207850 - user/imp/masq/sys/kern X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 May 2010 16:35:14 -0000 Author: imp Date: Mon May 10 16:35:13 2010 New Revision: 207850 URL: http://svn.freebsd.org/changeset/base/207850 Log: Write routines to walk through lists of mapping information to allow us to map new device IDs to old and a few other things. Modified: user/imp/masq/sys/kern/bus_if.m user/imp/masq/sys/kern/subr_bus.c Modified: user/imp/masq/sys/kern/bus_if.m ============================================================================== --- user/imp/masq/sys/kern/bus_if.m Mon May 10 15:28:44 2010 (r207849) +++ user/imp/masq/sys/kern/bus_if.m Mon May 10 16:35:13 2010 (r207850) @@ -141,6 +141,75 @@ METHOD int write_ivar { }; /** + * @brief Read the value of a bus-specific attribute of a device as a string + * + * This method will perform a mapping from the specified string to + * the bus specific ivar index, fetch the result from the ivar (or other + * location) and return the result as the most appropriate string for + * that resource. There's no reason why other attributes of the device + * on the bus than are embodied in the ivars, but generally such attributes + * don't make sense. + * + * @param _dev the device whose child was being examined + * @param _child the child device whose attribute is being read + * @param _attr the instance variable to read + * @param _result a loction to recieve the instance variable + * value + * @param _reslen Size of the buffer for the result. + * + * @retval 0 success + * @retval ENOATTR no such attribute is supported by @p _dev + * @retval EOVERFLOW value of @p _attr is longer than @p _reslen + */ +METHOD int read_attr { + device_t _dev; + device_t _child; + const char *_attr; + char *_result; + size_t _reslen; +}; + +/** + * @brief Write the value of a bus-specific attribute of a device + * + * This method sets the value of an attribute to @p _value. + * + * @param _dev the device whose child was being updated + * @param _child the child device whose attribute is being written + * @param _attr the instance variable to write + * @param _newval the new value to set + * + * @retval 0 success + * @retval ENOATTR no such attribute is supported by @p _dev + * @retval EINVAL cannot interpret @p _newval for @p _attr + * @retval EROFS cannot change @p _attr + */ +METHOD int write_attr { + device_t _dev; + device_t _child; + const char *_attr; + const char *_newval; +}; + +/** + * @brief As a bus to reset any modified attributes. + * + * Called when a new set of mapping tables are loaded into the kernel. The + * bus should re-read the attributes of the device from hardware and reset + * values stored in ivars or similar data structures to a base state (or + * it should restore the base state from a saved copy for buses that can + * only be enumerated once). Buses should make no assumptions about which + * devices have this called on them, nor the order of the calls. + * + * @param _dev the bus which the device to reset + * @param _child the child device to reset attributes for + */ +METHOD void reset_attr { + device_t _dev; + device_t _child; +}; + +/** * @brief Notify a bus that a child was detached * * Called after the child's DEVICE_DETACH() method to allow the parent Modified: user/imp/masq/sys/kern/subr_bus.c ============================================================================== --- user/imp/masq/sys/kern/subr_bus.c Mon May 10 15:28:44 2010 (r207849) +++ user/imp/masq/sys/kern/subr_bus.c Mon May 10 16:35:13 2010 (r207850) @@ -130,6 +130,7 @@ struct device { #define DF_DONENOMATCH 32 /* don't execute DEVICE_NOMATCH again */ #define DF_EXTERNALSOFTC 64 /* softc not allocated by us */ #define DF_REBID 128 /* Can rebid after attach */ +#define DF_REMAPPED 256 /* all remapping completed */ u_char order; /**< order from device_add_child_ordered() */ u_char pad; void *ivars; /**< instance variables */ @@ -142,6 +143,35 @@ struct device { static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); static MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc"); +/** + * @brief Generic remapping glue + */ +typedef TAILQ_HEAD(bus_map_attr_list, bus_map_attr) bus_map_attr_list_t; +typedef TAILQ_HEAD(bus_map_entry_list, bus_map_entry) bus_map_entry_list_t; +typedef TAILQ_HEAD(bus_remap_list, bus_remap) bus_remap_list_t; + +struct bus_map_attr +{ + TAILQ_ENTRY(bus_map_attr) link; /**< list of buses */ + const char* name; + const char* value; +}; + +struct bus_map_entry +{ + TAILQ_ENTRY(bus_map_entry) link; /**< list of buses */ + bus_map_attr_list_t match_list; + bus_map_attr_list_t map_list; +}; + +struct bus_remap +{ + TAILQ_ENTRY(bus_remap) link; /**< list of buses */ + const char* name; /**< Name of bus for this table */ + bus_map_entry_list_t map_list; +}; +static bus_remap_list_t bus_remaps = TAILQ_HEAD_INITIALIZER(bus_remaps); + #ifdef BUS_DEBUG static int bus_debug = 1; @@ -1915,6 +1945,81 @@ next_matching_driver(devclass_t dc, devi /** * @internal + * + * See if we can find remapping information for this device. Remapping a + * device means that we change, based on user input, the pnp information that + * the bus layer reports to the device. This is primarily intended to allow + * for fast updates in supported devices that are largely compatible with + * some prior device that's completely supported by the kernel. This pnp + * information is exported via the BUS_READ_ATTR and BUS_WRITE_ATTR functions + * and should be documented in each bus' man page. + */ +static void +device_remap_child(device_t bus, device_t child) +{ + char buffer[128]; + int rv; + struct bus_remap *busmap; + struct bus_map_entry *mapentry; + struct bus_map_attr *attr; + + /* + * XXXimp: Locking note + * When getting rid of GIANT, we need a global lock to regulate + * access to the device mapping structures. We also assume that + * @p child's parent is @p bus and that won't change until after + * we return. + */ + GIANT_REQUIRED; + + /* + * Only do the mapping once. + */ + if (child->flags & DF_REMAPPED) + return; + child->flags |= DF_REMAPPED; + + /* + * Check to see if this bus has a mapping table. If so, see if + * we can find a mapping entry that matches this device. If we + * find that, then remap the attributes in the remapping entry. + */ + TAILQ_FOREACH(busmap, &bus_remaps, link) { + if (strcmp(busmap->name, device_get_name(bus)) != 0) + continue; + break; + } + if (busmap == NULL) + return; + TAILQ_FOREACH(mapentry, &busmap->map_list, link) { + TAILQ_FOREACH(attr, &mapentry->match_list, link) { + if ((rv = BUS_READ_ATTR(bus, child, attr->name, + buffer, sizeof(buffer))) != 0) { + device_printf(bus, "Bad read attr %d, aborted rule.\n", rv); + break; + } + if (strcmp(attr->value, buffer) != 0) + break; + } + if (attr != NULL) + continue; + TAILQ_FOREACH(attr, &mapentry->map_list, link) { + rv = BUS_WRITE_ATTR(bus, child, attr->name, + attr->value); + if (rv != 0) { + device_printf(bus, + "Cannot map attribute %s to %s: error %d", + attr->name, attr->value, rv); + /* XXX Reset? Some other error recovery? */ + return; + } + } + } + return; +} + +/** + * @internal */ int device_probe_child(device_t dev, device_t child) @@ -1935,9 +2040,17 @@ device_probe_child(device_t dev, device_ * If the state is already probed, then return. However, don't * return if we can rebid this object. */ - if (child->state == DS_ALIVE && (child->flags & DF_REBID) == 0) + if ((child->state == DS_ALIVE && (child->flags & DF_REBID) == 0) || + child->state > DS_ALIVE) return (0); + /* + * Try to remap the pnp info for this device, if we haven't already + * done so. Remapping is a property of the DEVICE, not the driver + * that has attached to it. + */ + device_remap_child(dev, child); + for (; dc; dc = dc->parent) { for (dl = first_matching_driver(dc, child); dl;