Merged branches/developer/axeld/driver_recognition changed r12307:12637 into trunk.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12638 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-05-12 03:27:44 +00:00
parent cbd1d9977f
commit 6094d89f2f
46 changed files with 2901 additions and 2806 deletions
+15 -22
View File
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
PCI bus manager PCI bus manager
@@ -11,10 +11,9 @@
#define _PCI2_H #define _PCI2_H
#include <device_manager.h> #include <device_manager.h>
//#include "r5_wrapper.h"
#include <PCI.h> #include <PCI.h>
// currently, this structure is disables to avoid collision with R5 header // currently, this structure is disabled to avoid collision with R5 header
#if 0 #if 0
typedef struct pci_info { typedef struct pci_info {
@@ -89,26 +88,22 @@ typedef struct pci_device_info *pci_device;
typedef struct pci_device_module_info { typedef struct pci_device_module_info {
driver_module_info info; driver_module_info info;
uint8 (*read_io_8) (pci_device device, int mapped_io_addr); uint8 (*read_io_8)(pci_device device, int mapped_io_addr);
void (*write_io_8) (pci_device device, int mapped_io_addr, uint8 value); void (*write_io_8)(pci_device device, int mapped_io_addr, uint8 value);
uint16 (*read_io_16) (pci_device device, int mapped_io_addr); uint16 (*read_io_16)(pci_device device, int mapped_io_addr);
void (*write_io_16) (pci_device device, int mapped_io_addr, uint16 value); void (*write_io_16)(pci_device device, int mapped_io_addr, uint16 value);
uint32 (*read_io_32) (pci_device device, int mapped_io_addr); uint32 (*read_io_32)(pci_device device, int mapped_io_addr);
void (*write_io_32) (pci_device device, int mapped_io_addr, uint32 value); void (*write_io_32)(pci_device device, int mapped_io_addr, uint32 value);
uint32 (*read_pci_config) ( uint32 (*read_pci_config)(pci_device device,
pci_device device,
uchar offset, /* offset in configuration space */ uchar offset, /* offset in configuration space */
uchar size /* # bytes to read (1, 2 or 4) */ uchar size); /* # bytes to read (1, 2 or 4) */
); void (*write_pci_config)(pci_device device,
void (*write_pci_config) (
pci_device device,
uchar offset, /* offset in configuration space */ uchar offset, /* offset in configuration space */
uchar size, /* # bytes to write (1, 2 or 4) */ uchar size, /* # bytes to write (1, 2 or 4) */
uint32 value /* value to write */ uint32 value); /* value to write */
);
void * (*ram_address) (pci_device device, const void *physical_address_in_system_memory); void *(*ram_address)(pci_device device, const void *physical_address_in_system_memory);
/* status_t (*allocate_iomem)( void *base, size_t len, const char *name ); /* status_t (*allocate_iomem)( void *base, size_t len, const char *name );
status_t (*release_iomem)( void *base, size_t len ); status_t (*release_iomem)( void *base, size_t len );
@@ -118,8 +113,6 @@ typedef struct pci_device_module_info {
} pci_device_module_info; } pci_device_module_info;
// type of PCI device
#define PCI_DEVICE_TYPE_NAME "pci/device/v1"
// directory of PCI drivers // directory of PCI drivers
#define PCI_DRIVERS_DIR "pci" #define PCI_DRIVERS_DIR "pci"
+60 -413
View File
@@ -2,136 +2,10 @@
* Copyright 2004-2005, Haiku Inc. All Rights Reserved. * Copyright 2004-2005, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
*/ */
/*
Copyright (c) 2003-04, Thomas Kurschel
PnP manager; Takes care of registration and loading of PnP drivers
Read pnp_driver.h first to understand the basic idea behind PnP drivers.
To register a driver node, use register_driver. If the device got lost,
use unregister_driver (note: if the parent node is removed, your node
get removed automatically as your driver has obviously nothing to work
with anymore). To get access to a (parent) device, use load_driver/
unload_driver.
To let the manager find a consumer (see pnp_driver.h), you can either
specify its name directly during registration, using a
PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the
appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute.
Searching of dynamic consumers is done as follows:
- First, the manager searches for a Specific driver in the base
directory (see below)
- If no Specific driver is found, all Generic drivers stored under
"generic" sub-directory are informed in turn until one returns success
- Finally, _all_ Universal drivers, stored in the "universal" sub-
directory, are informed
Specification of the base directory and of the names of Specific
drivers is done via a file name pattern given by a
PNP_DRIVER_DYNAMIC_CONSUMER attribute.
First, all substrings of the form "%attribute_name%" are replaced by the
content of the attribute "attribute_name" as follows:
- if the attribute contains an integer value, its content is converted to hex
(lowercase) with a fixed length according to the attribute's value range
- the content of string attributes is quoted by " and invalid characters
(i.e. /%" and all characters outside 32..126) are replaced by their
unsigned decimal value, delimited by %
- other attribute types cannot be used
Second, the resulting name is split into chunks according to the presence
of | characters (you can escape % and | with a ^ character). These
characters are only delimiters and get removed before further processing.
The directory before the first | character is the base directory (see
above). It contains the "generic" and the "universal" subdirectories.
The names of the specific drivers are created by first taking the entire
file name, then by removing the last chunk, then by removing the last
two chunks and so on until only the first chunk is left.
As drivers can contain multiple modules, the module name is constructed
by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file
name, seperated by a slash character (note: this only applies to dynamic
consumers; for fixed consumers, you specify the module name directly via
PNP_DRIVER_FIXED_CONSUMER).
E.g. given a dynamic consumer pattern of
"pci/vendor=%vendor_id%|, device=%device_id%" for a device with the
attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the
PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and
(if the first one fails/doesn't exist) "pci/vendor=0123". If they both
refuse to handle the device, all drivers under "pci/generic" are tried
until one accepts the device. Finally, all drivers under "pci/universal"
are loaded, whatever happened before.
In practise, you should try to use specific drivers as much as possible.
If detection based on device IDs is impossible (e.g. because the bus
doesn't support them at all), you can put the driver under "generic".
Generic drivers can also be used to specify wrappers that try to load old-
style drivers if no new driver can be found. Also, they can be used to
report an error or invoke an user program that tries downloading a
proper Specific driver. Universal drivers are mainly used for
informational purposes, e.g. to publish data about each found device,
or to provide raw access to all devices.
If the device uses physical address space or I/O space or ISA DMA
channels (called I/O resources), the driver has to acquire these
resources. During hardware detection (usually via probe()),
acquire_io_resources() must be called to get exclusive access.
If no hardware could be found, they must be released via
release_io_resources(). If detection was successful, the list of
the (acquired) resources must be passed to register_device().
Resources can either belong to one hardware detection or to a device.
If a hardware detection collides with another, it has to wait;
if it collides with a device whose driver is not loaded, the
driver loading is blocked. When detection fails, i.e. if
release_io_resources() is called, all blocked drivers can be loaded
again. If the detection fails, i.e. the resources are transferred
via register_device(), all blocked devices are unregistered and
pending load requests aborted. If a hardware detection collides
with a device whose driver is loaded, acquire_io_resources() fails
with B_BUSY. As this makes a hardware rescan impossible if the
driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN
for nodes that use I/O resources (see below).
To search for new drivers for a given device node, use rescan(). This
marks all consumer devices as being verified and calls probe()
of all consumers drivers (see above) to let them rescan the parent
for devices. The <depth> parameter determines the nesting level, e.g.
2 means that first the consumers are scanned and then the consumers
of the consumers.
Normally, all devices can be rescanned. If a driver cannot handle
a rescan safely when it is loaded (i.e. used by a consumer), it
must set PNP_DRIVER_NO_LIVE_RESCAN, in which case the device is
ignored during rescan if the driver is loaded and attempts
to load the driver during a rescan are blocked until the rescan
is finished. If rescanning a device is not possible at all, it must
have set PNP_DRIVER_NEVER_RESCAN to always ignore it.
To distinguish between new devices, lost devices and redetected
devices, consumer devices should provide a connection code and a
device identifier. They are specified by PNP_DRIVER_CONNECTION and
PNP_DRIVER_CONNECTION respectively, and are expanded in the same way
as PNP_DRIVER_DYNAMIC_CONSUMER. It is assumed that there can be only
one device per connection and that a device can be uniquely identify
by a device identifier. If a consumer device is registered on the
same connection as an existing device but with a different device
identifier, the old device gets unregistered automatically. If both
connection and device identifier are the same, registration is
handled as a redetection and ignored (unless a different type or
driver module is specified - in this case, the device is replaced).
Devices that were not redetected during a rescan get unregistered
unless they were ignored (see above).
*/
#ifndef _DEVICE_MANAGER_H #ifndef _DEVICE_MANAGER_H
#define _DEVICE_MANAGER_H #define _DEVICE_MANAGER_H
#include <TypeConstants.h> #include <TypeConstants.h>
#include <Drivers.h> #include <Drivers.h>
#include <module.h> #include <module.h>
@@ -155,7 +29,7 @@ typedef struct {
// I/O port: first port address (16 bit) // I/O port: first port address (16 bit)
// ISA DMA channel: channel number (0-7) // ISA DMA channel: channel number (0-7)
uint32 len; uint32 length;
// I/O memory: size of address range (32 bit) // I/O memory: size of address range (32 bit)
// I/O port: size of port range (16 bit) // I/O port: size of port range (16 bit)
// ISA DMA channel: must be 1 // ISA DMA channel: must be 1
@@ -173,98 +47,48 @@ typedef struct {
const char *string; // B_STRING_TYPE const char *string; // B_STRING_TYPE
struct { // B_RAW_TYPE struct { // B_RAW_TYPE
void *data; void *data;
size_t len; size_t length;
} raw; } raw;
} value; } value;
} device_attr; } device_attr;
// handle of device node
typedef struct device_node_info *device_node_handle; typedef struct device_node_info *device_node_handle;
// handle of acquired I/O resource
typedef struct io_resource_info *io_resource_handle; typedef struct io_resource_info *io_resource_handle;
// handle of node attribute
typedef struct device_attr_info *device_attr_handle; typedef struct device_attr_info *device_attr_handle;
typedef struct driver_module_info driver_module_info; typedef struct driver_module_info driver_module_info;
// interface of PnP manager
// interface of the device manager
typedef struct device_manager_info { typedef struct device_manager_info {
module_info info; module_info info;
// load driver status_t (*init_driver)(device_node_handle node, void *userCookie,
// node - node whos driver is to be loaded
// user_cookie - cookie to be passed to init_device of driver
// interface - interface of loaded driver
// cookie - device cookie issued by loaded driver
status_t (*load_driver)(device_node_handle node, void *userCookie,
driver_module_info **interface, void **cookie); driver_module_info **interface, void **cookie);
// unload driver status_t (*uninit_driver)(device_node_handle node);
status_t (*unload_driver)(device_node_handle node);
// rescan node for new dynamic drivers status_t (*rescan)(device_node_handle node);
// node - node whose dynamic drivers are to be scanned
// depth - recursive depth (>= 1)
status_t (*rescan)(device_node_handle node, uint32 depth);
// register device
// parent - parent node
// attributes - NULL-terminated array of node attributes
// io_resources - NULL-terminated array of I/O resources (can be NULL)
// node - new node handle
// on return, io_resources are invalid: on success I/O resources belong
// to node, on fail they are released;
// if device is already registered, B_OK is returned but *node is NULL
status_t (*register_device)(device_node_handle parent, status_t (*register_device)(device_node_handle parent,
const device_attr *attrs, const device_attr *attrs,
const io_resource_handle *io_resources, const io_resource_handle *io_resources,
device_node_handle *node); device_node_handle *node);
// unregister device
// all nodes having this node as their parent are unregistered too.
// if the node contains PNP_MANAGER_ID_GENERATOR/PNP_MANAGER_AUTO_ID
// pairs, the id specified this way is freed too
status_t (*unregister_device)(device_node_handle node); status_t (*unregister_device)(device_node_handle node);
// acquire I/O resources status_t (*get_next_child_device)(device_node_handle parent,
// resources - NULL-terminated array of resources to acquire device_node_handle *_node, const device_attr *attrs);
// handles - NULL-terminated array of handles (one per resource); device_node_handle (*get_parent)(device_node_handle node);
// array must be provided by caller void (*put_device_node)(device_node_handle node);
// return B_BUSY if a resource is used by a loaded driver
status_t (*acquire_io_resources)(io_resource *resources, status_t (*acquire_io_resources)(io_resource *resources,
io_resource_handle *handles); io_resource_handle *handles);
// release I/O resources
// handles - NULL-terminated array of handles
status_t (*release_io_resources)(const io_resource_handle *handles); status_t (*release_io_resources)(const io_resource_handle *handles);
// find device by node content
// the given attributes must _uniquely_ identify a device node;
// parent - parent node (-1 for don't-care)
// attrs - list of attributes (can be NULL)
// return: NULL if no device or multiple(!) devices found
device_node_handle (*find_device)(device_node_handle parent,
const device_attr *attrs);
// create unique id
// generator - name of id set
// if result >= 0 - unique id
// result < 0 - error code
int32 (*create_id)(const char *generator); int32 (*create_id)(const char *generator);
// free unique id
status_t (*free_id)(const char *generator, uint32 id); status_t (*free_id)(const char *generator, uint32 id);
// get parent device node
device_node_handle (*get_parent)(device_node_handle node);
// helpers to extract attribute by name.
// if <recursive> is true, parent nodes are scanned if
// attribute isn't found in current node; unless you declared
// the attribute yourself, use recursive search to handle
// intermittent nodes, e.g. defined by filter drivers, transparently.
// for raw and string attributes, you get a copy that must
// be freed by caller
status_t (*get_attr_uint8)(device_node_handle node, status_t (*get_attr_uint8)(device_node_handle node,
const char *name, uint8 *value, bool recursive); const char *name, uint8 *value, bool recursive);
status_t (*get_attr_uint16)(device_node_handle node, status_t (*get_attr_uint16)(device_node_handle node,
@@ -279,272 +103,95 @@ typedef struct device_manager_info {
const char *name, void **data, size_t *_size, const char *name, void **data, size_t *_size,
bool recursive); bool recursive);
// get next attribute of node;
// on call, *<attr_handle> must contain handle of an attribute;
// on return, *<attr_handle> is replaced by the next attribute or
// NULL if it was the last;
// to get the first attribute, <attr_handle> must point to NULL;
// the returned handle must be released by either passing it to
// another get_next_attr() call or by using release_attr()
// directly
status_t (*get_next_attr)(device_node_handle node, status_t (*get_next_attr)(device_node_handle node,
device_attr_handle *attrHandle); device_attr_handle *attrHandle);
// release attribute handle <attr_handle> of <node>;
// see get_next_attr
status_t (*release_attr)(device_node_handle node, status_t (*release_attr)(device_node_handle node,
device_attr_handle attr_handle); device_attr_handle attr_handle);
// retrieve attribute data with handle given;
// <attr> is only valid as long as you don't release <attr_handle>
// implicitely or explicitely
status_t (*retrieve_attr)(device_attr_handle attr_handle, status_t (*retrieve_attr)(device_attr_handle attr_handle,
const device_attr **attr); const device_attr **attr);
// change/add attribute <attr> of/to node
status_t (*write_attr)(device_node_handle node, status_t (*write_attr)(device_node_handle node,
const device_attr *attr); const device_attr *attr);
// remove attribute of node by name
// <name> is name of attribute
status_t (*remove_attr)(device_node_handle node, const char *name); status_t (*remove_attr)(device_node_handle node, const char *name);
} device_manager_info; } device_manager_info;
// standard attributes: #define B_DEVICE_MANAGER_MODULE_NAME "system/device_manager/v1"
// if you are using an id generator (see create_id), you can let the
// manager automatically free the id when the node is deleted by setting
// the following attributes:
// name of generator (string)
#define PNP_MANAGER_ID_GENERATOR "id_generator"
// generated id (uint32)
#define PNP_MANAGER_AUTO_ID "auto_id"
// modulename of PnP manager
#define DEVICE_MANAGER_MODULE_NAME "sys/device_manager/v1"
// former pnp_driver.h
/*
Copyright (c) 2003-04, Thomas Kurschel
Required interface of PnP drivers
In contrast to standard BeOS drivers, PnP drivers are normal modules
having the interface described below.
Every device is described by its driver via a PnP node with properties
described in PnP Node Attributes. Devices are organized in a hierarchy,
e.g. a devfs device is a hard disk device that is connected to a
controller, which is a PCI device, that is connected to a PCI bus.
Every device is connected to its lower-level device via a parent link
stored in its Node. The higher-level is called the consumer of the
lower-level device. If the lower-level device gets removed, all its
consumers are removed too.
In our example, the hierarchy is
devfs device -> hard disk -> controller -> PCI device -> PCI bus
If the PCI bus is removed, everything up to including the devfs device
is removed too.
The driver hierarchy is constructed bottom-up, i.e. the lower-level
driver searches for a corresponding consumer, which in turns searches
for its consumer and so on. The lowest driver is usually something like
a PCI bus, the highest driver is normally a devfs entry (see pnp_devfs.h).
Registration of devices and the search for appropriate consumers is
done via the pnp_manager (see pnp_manager.h).
When a potential consumer is found, it gets informed about the new
lower-level device and can either refuse its handling or accept it.
On accept, it has to create a new node with the lower-level device
node as its parent.
Loading of drivers is done on demand, i.e. if the consumer wants to
access its lower-level device, it explicitely loads the corresponding
driver, and once it doesn't need it anymore, the lower-level driver
must be unloaded. Usually, this process happens recursively, i.e. in
our example, the hard disk driver loads the controller driver, which
loads the PCI device driver which loads the PCI bus driver. The same
process applies to unloading.
Because of this dynamic loading, drivers must store persistent data
in the node of their devices. Please be aware that you cannot modify
a node once published.
If a device gets removed, you must unregister its node. As said, the
PnP manager will automatically unregister all consumers too. The
corresponding drivers are notified to stop talking to their lower-level
devices and to terminate running requests. Normally, you want to use a
dedicated variable that is verified at each call to make sure that the
parent is still there. The notification is done independantly of the
driver being loaded by its consumer(s) or not. If it isn't loaded,
the notification callback gets NULL as the device cookie; normally, the
driver returns immediately in this case. As soon as both the device
is removed and the driver is unloaded, device_cleanup gets called to
free resources that couldn't be safely removed in device_removed when
the driver was still loaded.
If a device has exactly one consumer, they often interact in some way.
To simplify that, the consumer can pass a user-cookie to its parent
during load. In this case, it's up to the parent driver to get a
pointer to the interface of the consumer. Effectively, such consumers
have one interface for their consumers (base on pnp_driver_info), and
a another for their parents (with a completely driver-specific
structure).
In terms of synchronization, loading/unloading/remove-notifications
are executed synchroniously, i.e. if e.g. a device is to be unloaded
but the drive currently handles a remove-notification, the unloading
is delayed until the nofication callback returns. If multiple consumers
load a driver, the driver gets initialized only once; subsequent load
requests increase an internal load count only and return immediately.
In turn, unloading only happens once the load count reaches zero.
*/
// interface of device driver // interface of device driver
struct driver_module_info { struct driver_module_info {
module_info info; module_info info;
status_t (*init_device)(device_node_handle node, void *user_cookie, void **cookie); float (*supports_device)(device_node_handle parent, bool *_noConnection);
// driver is loaded.
// node - node of device
// user_cookie - cookie passed by loading driver
// cookie - cookie issued by this driver
status_t (*uninit_device)(void *cookie);
// driver gets unloaded.
status_t (*register_device)(device_node_handle parent); status_t (*register_device)(device_node_handle parent);
// parent was added or is rescanned.
// check whether this parent is supported and register status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie);
// any consumer device. Dynamic consumers must return status_t (*uninit_driver)(void *cookie);
// B_OK if they support this parent. All other return
// values are ignored.
void (*device_removed)(device_node_handle node, void *cookie); void (*device_removed)(device_node_handle node, void *cookie);
// a device node, registered by this driver, got removed.
// if the driver wasn't loaded when this happenes, no (un)init_device
// is called and thus <cookie> is NULL;
void (*device_cleanup)(device_node_handle node); void (*device_cleanup)(device_node_handle node);
// a device node, registered by this driver, got removed and
// the driver got unloaded void (*get_supported_paths)(const char ***_busses, const char ***_devices);
}; };
// standard attributes: // standard device node attributes
// module name of driver (required, string) #define PNP_MANAGER_ID_GENERATOR "id_generator"
#define PNP_DRIVER_DRIVER "driver" // if you are using an id generator (see create_id), you can let the
// type of driver (required, string) // manager automatically free the id when the node is deleted by setting
#define PNP_DRIVER_TYPE "type" // the following attributes:
// module name of fixed consumer - see pnp_manager.h (optional, string) // name of generator (string)
// append "/0", "/1" etc. if there are multiple fixed consumers #define PNP_MANAGER_AUTO_ID "auto_id"
#define PNP_DRIVER_FIXED_CONSUMER "consumer/fixed" // generated id (uint32)
// dynamic consumers pattern - see pnp_manager.h (optional, string)
// append "/0", "/1" etc. if there are multiple dynamic consumers #define B_DRIVER_MODULE "driver/module"
#define PNP_DRIVER_DYNAMIC_CONSUMER "consumer/dynamic" #define B_DRIVER_PRETTY_NAME "driver/pretty name"
#define B_DRIVER_FIXED_CHILD "driver/fixed child"
#define B_DRIVER_MAPPING "driver/mapping"
#define B_DRIVER_BUS "driver/bus"
#define B_DRIVER_FIND_DEVICES_ON_DEMAND "driver/on demand"
#define B_DRIVER_EXPLORE_LAST "driver/explore last"
#define B_DRIVER_UNIQUE_DEVICE_ID "unique id"
#define B_DRIVER_DEVICE_TYPE "device type"
#define B_AUDIO_DRIVER_TYPE "audio"
#define B_BUS_DRIVER_TYPE "bus"
#define B_DISK_DRIVER_TYPE "disk"
#define B_GRAPHICS_DRIVER_TYPE "graphics"
#define B_INPUT_DRIVER_TYPE "input"
#define B_MISC_DRIVER_TYPE "misc"
#define B_NETWORK_DRIVER_TYPE "net"
#define B_VIDEO_DRIVER_TYPE "video"
// connection of parent the device is attached to (optional, string)
// there can be only one device per connection
#define PNP_DRIVER_CONNECTION "connection" #define PNP_DRIVER_CONNECTION "connection"
// pattern device identifier (optional, string) // connection of parent the device is attached to (optional, string)
// it is expanded and used to detect changed devices // there can be only one device per connection
#define PNP_DRIVER_DEVICE_IDENTIFIER "device_identifier"
// driver must not be loaded during rescan (optional, uint8)
// if != 0, driver must not be loaded during rescan
// nor can rescan be started when driver is loaded
// if the device uses I/O resources, you _must_ set this
// flag as the rescan would always fail if the driver is loaded
// due to resource contention
#define PNP_DRIVER_NO_LIVE_RESCAN "no_live_rescan"
// never rescan this device (optional, uint8)
// if != 0, device is never checked during rescan
#define PNP_DRIVER_NEVER_RESCAN "never_rescan"
// keep driver loaded loaded (optional, uint8)
// if != 0, the driver is loaded automatically whenever the node
// is registered and unloaded whenever the node is unregistered.
// if = 1, driver is temporarily unloaded during rescan
// if = 2, driver is not unloaded during rescan
// avoid the second case (2) as this makes replacing the driver
// impossible without a reboot.
#define PNP_DRIVER_ALWAYS_LOADED "always_loaded"
// former pnp_bus.h // interface of a bus device driver
/*
Copyright (c) 2003-04, Thomas Kurschel
Required interface of PnP bus drivers
Busses consist of two node layers: the lower layer defines the bus,
the upper layer defines the abstract devices connected to the bus.
Both layers are handled by a bus manager. Actual device nodes are
on top of abstract device nodes.
E.g. if we have a PCI bus with an IDE controller on it, we get
IDE controller -> PCI device -> PCI bus
with:
IDE controller = actual device node
PCI device = abstract device node
PCI bus = bus node
The PCI bus manager establishes both the PCI devices and the PCI busses.
Abstract device nodes act as a gateway between actual device nodes
and the corresponding bus node. They are constructed by the bus
node driver via its rescan() hook. To identify a bus node, define
PNP_BUS_IS_BUS as an attribute of it. As a result, the PnP manager
will call the rescan() method of the bus driver whenever the
bus is to be rescanned. Afterwards, all possible dynamic consumers
are informed as done for normal nodes.
Normally, potential device drivers are notified immediately when
rescan() registers a new abstract device node. But sometimes, device
drivers need to know _all_ devices connected to the bus for correct
detection. To ensure this, the bus node must define
PNP_BUS_NOTIFY_CONSUMERS_AFTER_RESCAN. In this case, scanning for
consumers is postponed until rescan() has finished.
If hot-plugging of devices can be detected automatically (e.g. USB),
you should define PNP_DRIVER_ALWAYS_LOADED, so the bus driver is
always loaded and thus capable of handling hot-plug events generated
by the bus controller hardware.
*/
// interface of PnP bus
typedef struct bus_module_info { typedef struct bus_module_info {
driver_module_info info; driver_module_info info;
// (re)scan bus and register all devices. // scan the bus and register all devices.
status_t (*register_child_devices)(void *cookie);
// user initiated rescan of the bus - only propagate changes
// you only need to implement this, if you cannot detect device changes yourself
// driver is always loaded during this call, but other hooks may // driver is always loaded during this call, but other hooks may
// be called concurrently // be called concurrently
status_t (*rescan) (void *cookie); status_t (*rescan_bus)(void *cookie);
} bus_module_info; } bus_module_info;
// standard attributes: // standard attributes
// PnP bus identification (required, uint8) // PnP bus identification (required, uint8)
// define this to let the PnP manager know that this is a PnP bus // define this to let the PnP manager know that this is a PnP bus
// the actual content is ignored // the actual content is ignored
#define PNP_BUS_IS_BUS "bus/is_bus" #define PNP_BUS_IS_BUS "bus/is_bus"
// defer searching for consumers (optional, uint8)
// if != 0, probe() of consumers is called after rescan() of bus
// else, probe() of consumers is called during rescan() of bus
// normally, consumers are informed about a new device as soon as
// it is registered by rescan(), i.e. not all devices may have been
// detected and registered yet;
// with this flag, detection of consumers is postponed until
// rescan() has finished, i.e. when all devices are registered
#define PNP_BUS_DEFER_PROBE "bus/defer_probe"
#endif /* _DEVICE_MANAGER_H */ #endif /* _DEVICE_MANAGER_H */
+6 -8
View File
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
PnP devfs driver interface. PnP devfs driver interface.
@@ -20,9 +20,10 @@
#ifndef _PNP_DEVFS_H #ifndef _PNP_DEVFS_H
#define _PNP_DEVFS_H #define _PNP_DEVFS_H
#include <Drivers.h> #include <Drivers.h>
#include <device_manager.h> #include <device_manager.h>
//#include "r5_wrapper.h"
// changed open hook - gets cookie returned by init_device instead of name // changed open hook - gets cookie returned by init_device instead of name
typedef status_t (*pnp_device_open_hook)(void *device_cookie, uint32 flags, typedef status_t (*pnp_device_open_hook)(void *device_cookie, uint32 flags,
@@ -49,9 +50,6 @@ typedef struct pnp_devfs_driver_info {
// name under which the device should be published under /dev (required, string) // name under which the device should be published under /dev (required, string)
#define PNP_DEVFS_FILENAME "devfs/filename" #define PNP_DEVFS_FILENAME "devfs/filename"
// type of devfs device drivers #define PNP_DEVFS_MODULE_NAME "system/devfs/device_v1"
#define PNP_DEVFS_TYPE_NAME "devfs_device"
#define PNP_DEVFS_MODULE_NAME "sys/pnp_devfs/v1"
#endif #endif
+7 -12
View File
@@ -9,25 +9,23 @@
#include <SupportDefs.h> #include <SupportDefs.h>
#include <device_manager.h> #include <device_manager.h>
#include <util/list.h>
typedef struct device_node_info device_node_info; typedef struct device_node_info device_node_info;
// info about a device node // info about a device node
struct device_node_info { struct device_node_info {
device_node_info *prev, *next; struct list_link siblings;
device_node_info *siblings_prev, *siblings_next;
device_node_info *notify_prev, *notify_next;
device_node_info *parent; device_node_info *parent;
device_node_info *children; struct list children;
int32 ref_count; // reference count; see registration.c int32 ref_count;
driver_module_info *driver; driver_module_info *driver;
void *cookie; void *cookie;
bool registered; // true, if device is officially existent bool registered; // true, if device is officially existent
bool init_finished; // true, if publish_device has been completed
// (sync with loader_lock)
bool blocked_by_rescan; // true, if device is blocked because of rescan bool blocked_by_rescan; // true, if device is blocked because of rescan
bool verifying; // true, if driver is being verified by rescan
bool redetected; // true, if driver was redetected during rescan
int32 num_waiting_hooks; // number of waiting hook calls int32 num_waiting_hooks; // number of waiting hook calls
sem_id hook_sem; // sem for waiting hook calls sem_id hook_sem; // sem for waiting hook calls
int32 load_block_count; // load-block nest count int32 load_block_count; // load-block nest count
@@ -39,10 +37,7 @@ struct device_node_info {
struct device_attr_info *attributes; // list of attributes struct device_attr_info *attributes; // list of attributes
uint32 num_io_resources; // number of I/O resources uint32 num_io_resources; // number of I/O resources
io_resource_handle *io_resources; // array of I/O resource (NULL-terminated) io_resource_handle *io_resources; // array of I/O resource (NULL-terminated)
int32 defer_probing; // > 0 defer probing for consumers of children
bool automatically_loaded; // loaded automatically because PNP_DRIVER_ALWAYS_LOADED bool automatically_loaded; // loaded automatically because PNP_DRIVER_ALWAYS_LOADED
device_node_info *unprobed_children; // list of un-probed children
device_node_info *unprobed_prev, *unprobed_next; // link for unprobed_children
}; };
+8 -14
View File
@@ -26,19 +26,14 @@
static status_t static status_t
ide_channel_added(device_node_handle parent) ide_channel_added(device_node_handle parent)
{ {
char *str = NULL, *controller_name = NULL; char *controller_name = NULL;
uint32 channel_id; uint32 channel_id;
SHOW_FLOW0(2, ""); SHOW_FLOW0(2, "");
if (pnp->get_attr_string(parent, PNP_DRIVER_TYPE, &str, false) != B_OK
|| strcmp(str, IDE_BUS_TYPE_NAME) != 0)
goto err;
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM, if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
&controller_name, true) != B_OK) { &controller_name, true) != B_OK) {
pnp->get_attr_string(parent, PNP_DRIVER_DRIVER, &str, false); dprintf("ide: ignored controller - controller name missing\n");
SHOW_ERROR( 0, "Ignored controller managed by %s - controller name missing", str);
goto err; goto err;
} }
@@ -52,9 +47,9 @@ ide_channel_added(device_node_handle parent)
{ {
device_attr attrs[] = device_attr attrs[] =
{ {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_SIM_TYPE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE, { SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ string: controller_name }}, { string: controller_name }},
// maximum number of blocks per transmission: // maximum number of blocks per transmission:
@@ -81,14 +76,12 @@ ide_channel_added(device_node_handle parent)
res = pnp->register_device(parent, attrs, NULL, &node); res = pnp->register_device(parent, attrs, NULL, &node);
free(str);
free(controller_name); free(controller_name);
return res; return res;
} }
err: err:
free(str);
free(controller_name); free(controller_name);
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -117,9 +110,10 @@ ide_for_controller_interface ide_for_controller_module = {
&std_ops &std_ops
}, },
NULL, NULL, // supported devices
NULL,
ide_channel_added, ide_channel_added,
NULL,
NULL,
NULL NULL
}, },
+33 -22
View File
@@ -34,6 +34,7 @@ scsi_for_sim_interface *scsi;
fast_log_info *fast_log; fast_log_info *fast_log;
#ifdef USE_FAST_LOG
static fast_log_event_type ide_events[] = static fast_log_event_type ide_events[] =
{ {
{ ev_ide_send_command, "ev_ide_send_command " }, { ev_ide_send_command, "ev_ide_send_command " },
@@ -64,9 +65,11 @@ static fast_log_event_type ide_events[] =
{ ev_ide_scan_device_int_found, "ev_ide_scan_device_int_found" }, { ev_ide_scan_device_int_found, "ev_ide_scan_device_int_found" },
{} {}
}; };
#endif
static void disconnect_worker( ide_bus_info *bus, void *arg );
static void set_check_condition( ide_qrequest *qrequest ); static void disconnect_worker(ide_bus_info *bus, void *arg);
static void set_check_condition(ide_qrequest *qrequest);
/** check whether this request can be within device */ /** check whether this request can be within device */
@@ -541,6 +544,7 @@ finish_all_requests(ide_device_info *device, ide_qrequest *ignore,
static status_t static status_t
ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie) ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
{ {
device_node_handle parent;
ide_bus_info *bus; ide_bus_info *bus;
int res; int res;
@@ -566,11 +570,13 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
sprintf(bus->name, "ide_bus %d", (int)channel_id); sprintf(bus->name, "ide_bus %d", (int)channel_id);
} }
#if 0
bus->log = fast_log->start_log(bus->name, ide_events); bus->log = fast_log->start_log(bus->name, ide_events);
if (bus->log == NULL) { if (bus->log == NULL) {
res = B_NO_MEMORY; res = B_NO_MEMORY;
goto err; goto err;
} }
#endif
init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker); init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker);
init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker); init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker);
@@ -635,9 +641,13 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
bus->can_CQ = false; bus->can_CQ = false;
} }
res = pnp->load_driver(pnp->get_parent(node), bus, parent = pnp->get_parent(node);
res = pnp->init_driver(parent, bus,
(driver_module_info **)&bus->controller, (driver_module_info **)&bus->controller,
(void **)&bus->channel); (void **)&bus->channel);
pnp->put_device_node(parent);
if (res != B_OK) if (res != B_OK)
goto err5; goto err5;
@@ -654,16 +664,15 @@ err4:
delete_sem(bus->scan_device_sem); delete_sem(bus->scan_device_sem);
err3: err3:
delete_sem(bus->sync_wait_sem); delete_sem(bus->sync_wait_sem);
err2: err2:
scsi->free_dpc(bus->irq_dpc); scsi->free_dpc(bus->irq_dpc);
err1: err1:
uninit_synced_pc(&bus->scan_bus_syncinfo); uninit_synced_pc(&bus->scan_bus_syncinfo);
uninit_synced_pc(&bus->disconnect_syncinfo); uninit_synced_pc(&bus->disconnect_syncinfo);
#ifdef USE_FAST_LOG
fast_log->stop_log(bus->log); fast_log->stop_log(bus->log);
err: err:
#endif
free(bus); free(bus);
return res; return res;
@@ -673,7 +682,10 @@ err:
static status_t static status_t
ide_sim_uninit_bus(ide_bus_info *bus) ide_sim_uninit_bus(ide_bus_info *bus)
{ {
pnp->unload_driver(pnp->get_parent(bus->node)); device_node_handle parent = pnp->get_parent(bus->node);
pnp->uninit_driver(parent);
pnp->put_device_node(parent);
DELETE_BEN(&bus->status_report_ben); DELETE_BEN(&bus->status_report_ben);
delete_sem(bus->scan_device_sem); delete_sem(bus->scan_device_sem);
@@ -681,7 +693,7 @@ ide_sim_uninit_bus(ide_bus_info *bus)
scsi->free_dpc(bus->irq_dpc); scsi->free_dpc(bus->irq_dpc);
uninit_synced_pc(&bus->scan_bus_syncinfo); uninit_synced_pc(&bus->scan_bus_syncinfo);
uninit_synced_pc(&bus->disconnect_syncinfo); uninit_synced_pc(&bus->disconnect_syncinfo);
fast_log->stop_log(bus->log); // fast_log->stop_log(bus->log);
free(bus); free(bus);
@@ -769,9 +781,8 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ FAST_LOG_MODULE_NAME, (module_info **)&fast_log },
{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&scsi }, { SCSI_FOR_SIM_MODULE_NAME, (module_info **)&scsi },
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -783,23 +794,23 @@ scsi_sim_interface ide_sim_module = {
0, 0,
std_ops, std_ops,
}, },
NULL, // supported devices
NULL, // register node
(status_t (*)(device_node_handle, void *, void **))ide_sim_init_bus, (status_t (*)(device_node_handle, void *, void **))ide_sim_init_bus,
(status_t (*)( void *)) ide_sim_uninit_bus, (status_t (*)(void *) ) ide_sim_uninit_bus,
NULL,
(void (*)(device_node_handle, void *)) ide_sim_bus_removed (void (*)(device_node_handle, void *)) ide_sim_bus_removed
}, },
(void (*)( scsi_sim_cookie, scsi_ccb * )) sim_scsi_io, (void (*)(scsi_sim_cookie, scsi_ccb *)) sim_scsi_io,
(uchar (*)( scsi_sim_cookie, scsi_ccb * )) sim_abort, (uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_abort,
(uchar (*)( scsi_sim_cookie, uchar, uchar )) sim_reset_device, (uchar (*)(scsi_sim_cookie, uchar, uchar)) sim_reset_device,
(uchar (*)( scsi_sim_cookie, scsi_ccb * )) sim_term_io, (uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_term_io,
(uchar (*)( scsi_sim_cookie, scsi_path_inquiry * )) sim_path_inquiry, (uchar (*)(scsi_sim_cookie, scsi_path_inquiry *))sim_path_inquiry,
(uchar (*)( scsi_sim_cookie )) sim_scan_bus, (uchar (*)(scsi_sim_cookie)) sim_scan_bus,
(uchar (*)( scsi_sim_cookie )) sim_reset_bus, (uchar (*)(scsi_sim_cookie)) sim_reset_bus,
(void (*)( scsi_sim_cookie, uchar, (void (*)(scsi_sim_cookie, uchar,
bool*, bool *, uint32 *)) ide_sim_get_restrictions bool*, bool *, uint32 *)) ide_sim_get_restrictions
}; };
+56 -46
View File
@@ -1,5 +1,7 @@
/* /*
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -31,7 +33,7 @@
// (for example, the Pegasos (PPC based) also has an ISA bus) // (for example, the Pegasos (PPC based) also has an ISA bus)
#define ISA_MODULE_NAME "bus_managers/isa/root" #define ISA_MODULE_NAME "bus_managers/isa/root/device_v1"
device_manager_info *pnp; device_manager_info *pnp;
@@ -96,6 +98,7 @@ static long
make_isa_dma_table(const void *buffer, long buffer_size, ulong num_bits, make_isa_dma_table(const void *buffer, long buffer_size, ulong num_bits,
isa_dma_entry *table, long num_entries) isa_dma_entry *table, long num_entries)
{ {
// ToDo: implement this?!
return ENOSYS; return ENOSYS;
} }
@@ -104,8 +107,7 @@ static status_t
start_isa_dma(long channel, void *buf, long transfer_count, start_isa_dma(long channel, void *buf, long transfer_count,
uchar mode, uchar e_mode) uchar mode, uchar e_mode)
{ {
// TBD // ToDo: implement this?!
// ToDo
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
} }
@@ -114,6 +116,7 @@ static long
start_scattered_isa_dma(long channel, const isa_dma_entry *table, start_scattered_isa_dma(long channel, const isa_dma_entry *table,
uchar mode, uchar emode) uchar mode, uchar emode)
{ {
// ToDo: implement this?!
return ENOSYS; return ENOSYS;
} }
@@ -121,8 +124,7 @@ start_scattered_isa_dma(long channel, const isa_dma_entry *table,
static status_t static status_t
lock_isa_dma_channel(long channel) lock_isa_dma_channel(long channel)
{ {
// TBD // ToDo: implement this?!
// ToDo
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
} }
@@ -130,14 +132,13 @@ lock_isa_dma_channel(long channel)
static status_t static status_t
unlock_isa_dma_channel(long channel) unlock_isa_dma_channel(long channel)
{ {
// TBD // ToDo: implement this?!
// ToDo
return B_ERROR; return B_ERROR;
} }
static status_t static status_t
isa_init_device(device_node_handle node, void *user_cookie, void **cookie) isa_init_driver(device_node_handle node, void *user_cookie, void **cookie)
{ {
*cookie = NULL; *cookie = NULL;
return B_OK; return B_OK;
@@ -145,52 +146,61 @@ isa_init_device(device_node_handle node, void *user_cookie, void **cookie)
static status_t static status_t
isa_uninit_device(void *cookie) isa_uninit_driver(void *cookie)
{ {
return B_OK; return B_OK;
} }
static float
isa_supports_device(device_node_handle parent, bool *_noConnection)
{
char *bus;
// make sure parent is really pnp root
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
return B_ERROR;
if (strcmp(bus, "root")) {
free(bus);
return 0.0;
}
free(bus);
return 1.0;
}
static status_t static status_t
isa_device_added(device_node_handle parent) isa_register_device(device_node_handle parent)
{ {
static const device_attr attrs[] = { static const device_attr attrs[] = {
// info about ourself // info about ourself
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: ISA_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: ISA_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: ISA_DEVICE_TYPE_NAME }},
// unique connection // unique connection
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }},
// mark as being a bus // mark as being a bus
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }}, { PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
// tell where to look for consumers // tell where to look for child devices
// ToDo: temporary hack to get things started! { B_DRIVER_BUS, B_STRING_TYPE, { string: "isa" }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "busses/ide/ide_isa/isa/device/v1" }}, { B_DRIVER_FIND_DEVICES_ON_DEMAND, B_UINT8_TYPE, { ui8: 1 }},
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string: ISA_DRIVERS_DIR "/" }}, { B_DRIVER_EXPLORE_LAST, B_UINT8_TYPE, { ui8: 1 }},
{ NULL } { NULL }
}; };
device_node_handle node; return pnp->register_device(parent, attrs, NULL, NULL);
char *parent_type; }
status_t res;
// make sure parent is really pnp root
if (pnp->get_attr_string( parent, PNP_DRIVER_TYPE, &parent_type, false))
return B_ERROR;
if (strcmp(parent_type, "pnp/root")) { static void
free(parent_type); isa_get_paths(const char ***_bus, const char ***_device)
return B_ERROR; {
} static const char *kBus[] = {"root", NULL};
free(parent_type);
res = pnp->register_device(parent, attrs, NULL, &node); *_bus = kBus;
if (res != B_OK) *_device = NULL;
return res;
return B_OK;
} }
@@ -209,7 +219,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -245,15 +255,19 @@ static isa2_module_info isa2_module = {
std_ops std_ops
}, },
isa_init_device, isa_supports_device,
isa_uninit_device, isa_register_device,
isa_device_added, isa_init_driver,
NULL isa_uninit_driver,
NULL, // removed device
NULL, // cleanup device
isa_get_paths,
}, },
// this rescan(); as ISA relies on device drivers to detect their // as ISA relies on device drivers to detect their devices themselves,
// devices themselves, we don't have an universal rescan method // we don't have an universal rescan method
NULL NULL, // register child devices
NULL, // rescan bus
}, },
isa_read_io_8, isa_write_io_8, isa_read_io_8, isa_write_io_8,
@@ -265,12 +279,8 @@ static isa2_module_info isa2_module = {
start_isa_dma, start_isa_dma,
}; };
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = { module_info *modules[] = {
(module_info *)&isa_module, (module_info *)&isa_module,
(module_info *)&isa2_module, (module_info *)&isa2_module,
NULL NULL
}; };
#endif
@@ -7,6 +7,7 @@ KernelAddon pci : kernel bus_managers :
pci.cpp pci.cpp
pci_info.cpp pci_info.cpp
pci_module.c pci_module.c
pci_device.c
kernel_cpp.cpp kernel_cpp.cpp
: pci_arch_bus_manager.a : pci_arch_bus_manager.a
; ;
+38 -5
View File
@@ -1,27 +1,60 @@
/*
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h> #include <KernelExport.h>
#include <PCI.h> #include <PCI.h>
#include "util/kernel_cpp.h" #include "util/kernel_cpp.h"
#include "pci_priv.h" #include "pci_priv.h"
#include "pci.h" #include "pci.h"
static PCI *pcidb;
void bool gIrqRouterAvailable = false;
spinlock gConfigLock = 0;
static PCI *sPCI;
status_t
pci_init(void) pci_init(void)
{ {
pcidb = new PCI; if (pci_io_init() != B_OK) {
TRACE(("PCI: pci_io_init failed\n"));
return B_ERROR;
}
if (pci_config_init() != B_OK) {
TRACE(("PCI: pci_config_init failed\n"));
return B_ERROR;
}
if (pci_irq_init() != B_OK)
TRACE(("PCI: IRQ router not available\n"));
else
gIrqRouterAvailable = true;
sPCI = new PCI;
return B_OK;
} }
void void
pci_uninit(void) pci_uninit(void)
{ {
delete pcidb; delete sPCI;
} }
long long
pci_get_nth_pci_info(long index, pci_info *outInfo) pci_get_nth_pci_info(long index, pci_info *outInfo)
{ {
return pcidb->GetNthPciInfo(index, outInfo); return sPCI->GetNthPciInfo(index, outInfo);
} }
+50 -36
View File
@@ -1,33 +1,36 @@
/*
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef __PCI_H__
#define __PCI_H__
#include <SupportDefs.h>
#ifdef __cplusplus
extern "C" {
#endif
#define TRACE_PCI #define TRACE_PCI
#ifndef TRACE_PCI #ifndef TRACE_PCI
#define TRACE(x) # define TRACE(x) ;
#else #else
#define TRACE(x) dprintf x # define TRACE(x) dprintf x
#endif #endif
void pci_init(void);
void pci_uninit(void);
long pci_get_nth_pci_info(long index, pci_info *outInfo);
#ifdef __cplusplus #ifdef __cplusplus
struct PCIBus; struct PCIBus;
struct PCIDev; struct PCIDev;
struct PCIBus struct PCIBus {
{
PCIDev *parent; PCIDev *parent;
uint8 bus; uint8 bus;
PCIDev *child; PCIDev *child;
}; };
struct PCIDev struct PCIDev {
{
PCIDev *next; PCIDev *next;
PCIBus *parent; PCIBus *parent;
PCIBus *child; PCIBus *child;
@@ -37,37 +40,48 @@ struct PCIDev
pci_info info; pci_info info;
}; };
class PCI class PCI {
{ public:
public: PCI();
PCI(); ~PCI();
~PCI();
status_t GetNthPciInfo(long index, pci_info *outInfo); status_t GetNthPciInfo(long index, pci_info *outInfo);
private: private:
void DiscoverBus(PCIBus *bus); void DiscoverBus(PCIBus *bus);
void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func); void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func);
PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func);
PCIBus *CreateBus(PCIDev *parent, uint8 bus);
status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo);
void ReadPciBasicInfo(PCIDev *dev);
void ReadPciHeaderInfo(PCIDev *dev);
void RefreshDeviceInfo(PCIBus *bus); PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func);
PCIBus *CreateBus(PCIDev *parent, uint8 bus);
uint32 BarSize(uint32 bits, uint32 mask);
void GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0); status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo);
void GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0); void ReadPciBasicInfo(PCIDev *dev);
void ReadPciHeaderInfo(PCIDev *dev);
private:
PCIBus fRootBus; void RefreshDeviceInfo(PCIBus *bus);
uint32 BarSize(uint32 bits, uint32 mask);
void GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
void GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
private:
PCIBus fRootBus;
}; };
#endif // __cplusplus #endif // __cplusplus
#ifdef __cplusplus
extern "C" {
#endif
status_t pci_init(void);
void pci_uninit(void);
long pci_get_nth_pci_info(long index, pci_info *outInfo);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __PCI_H__ */
@@ -0,0 +1,206 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2002-2003, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
PCI bus manager
PCI device layer. There is one node per PCI device.
The common root is the PCI root node.
*/
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include "pci_priv.h"
// information about one PCI device
typedef struct pci_device_info {
uint8 bus; // bus number
uint8 device; // device number
uint8 function; // function number
device_node_handle node;
pci_root_info *root; // parent, i.e. PCI root
char name[32]; // name (for fast log)
} pci_device_info;
static uint8
pci_device_read_io_8(pci_device_info *device, int mapped_io_addr)
{
return pci_read_io_8(mapped_io_addr);
}
static void
pci_device_write_io_8(pci_device_info *device, int mapped_io_addr, uint8 value)
{
pci_write_io_8(mapped_io_addr, value);
}
static uint16
pci_device_read_io_16(pci_device_info *device, int mapped_io_addr)
{
return pci_read_io_16(mapped_io_addr);
}
static void
pci_device_write_io_16(pci_device_info *device, int mapped_io_addr, uint16 value)
{
pci_write_io_16(mapped_io_addr, value);
}
static uint32
pci_device_read_io_32(pci_device_info *device, int mapped_io_addr)
{
return pci_read_io_32(mapped_io_addr);
}
static void
pci_device_write_io_32(pci_device_info *device, int mapped_io_addr, uint32 value)
{
pci_write_io_32(mapped_io_addr, value);
}
static uint32
pci_device_read_pci_config(pci_device_info *device, uint8 offset, uint8 size)
{
return device->root->read_pci_config(device->bus, device->device,
device->function, offset, size);
}
static void
pci_device_write_pci_config(pci_device device, uint8 offset, uint8 size, uint32 value)
{
return device->root->write_pci_config(device->bus, device->device,
device->function, offset, size, value);
}
static void *
pci_device_ram_address(pci_device_info *device,
const void *physical_address_in_system_memory)
{
return pci_ram_address(physical_address_in_system_memory);
}
static status_t
pci_device_init_driver(device_node_handle node, void *user_cookie, void **cookie)
{
uint8 bus, deviceNumber, function;
device_node_handle parent;
pci_device_info *device;
pci_root_info *root;
status_t status;
void *dummy;
if (gDeviceManager->get_attr_uint8(node, PCI_DEVICE_BUS_ITEM, &bus, false) != B_OK
|| gDeviceManager->get_attr_uint8(node, PCI_DEVICE_DEVICE_ITEM, &deviceNumber, false) != B_OK
|| gDeviceManager->get_attr_uint8(node, PCI_DEVICE_FUNCTION_ITEM, &function, false) != B_OK)
return B_ERROR;
parent = gDeviceManager->get_parent(node);
status = gDeviceManager->init_driver(parent, NULL, (driver_module_info **)&root, &dummy);
if (status != B_OK)
goto err;
device = malloc(sizeof(*device));
if (device == NULL) {
status = B_NO_MEMORY;
goto err;
}
gDeviceManager->put_device_node(parent);
memset(device, 0, sizeof(*device));
device->bus = bus;
device->device = deviceNumber;
device->function = function;
device->node = node;
device->root = root;
snprintf(device->name, sizeof(device->name), "pci_device %u:%u:%u",
bus, deviceNumber, function);
*cookie = device;
return B_OK;
err:
gDeviceManager->uninit_driver(parent);
gDeviceManager->put_device_node(parent);
return status;
}
static status_t
pci_device_uninit_driver(void *cookie)
{
pci_device_info *device = cookie;
device_node_handle parent;
parent = gDeviceManager->get_parent(device->node);
gDeviceManager->uninit_driver(parent);
gDeviceManager->put_device_node(parent);
free(device);
return B_OK;
}
static status_t
pci_device_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_BAD_VALUE;
}
pci_device_module_info gPCIDeviceModule = {
{
{
PCI_DEVICE_MODULE_NAME,
0,
pci_device_std_ops
},
NULL, // supports device
NULL, // register device (our parent registered us)
pci_device_init_driver,
pci_device_uninit_driver,
NULL, // removed
NULL, // cleanup
NULL, // get supported paths
},
pci_device_read_io_8,
pci_device_write_io_8,
pci_device_read_io_16,
pci_device_write_io_16,
pci_device_read_io_32,
pci_device_write_io_32,
pci_device_read_pci_config,
pci_device_write_pci_config,
pci_device_ram_address,
};
+213 -41
View File
@@ -1,85 +1,225 @@
/*
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h> #include <KernelExport.h>
#include <device_manager.h>
#include <bus_manager.h> #include <bus_manager.h>
#include <PCI.h> #include <PCI.h>
#include <string.h>
#include <stdlib.h>
#include "pci_priv.h" #include "pci_priv.h"
#include "pci_info.h" #include "pci_info.h"
#include "pci.h" #include "pci.h"
bool gIrqRouterAvailable = false;
spinlock gConfigLock = 0;
status_t pci_module_init(void); device_manager_info *gDeviceManager;
status_t pci_module_uninit(void);
int32 pci_module_std_ops(int32 op, ...);
status_t pci_module_rescan(void);
status_t
pci_module_init(void) // name of PCI root module
#define PCI_ROOT_MODULE_NAME "bus_managers/pci/root/device_v1"
static float
pci_module_supports_device(device_node_handle parent, bool *_noConnection)
{ {
TRACE(("PCI: pci_module_init\n")); char *bus;
if (B_OK != pci_io_init()) { // make sure parent is really device root
TRACE(("PCI: pci_io_init failed\n")); if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
return B_ERROR; return B_ERROR;
if (strcmp(bus, "root")) {
free(bus);
return 0.0;
} }
if (B_OK != pci_config_init()) { free(bus);
TRACE(("PCI: pci_config_init failed\n")); return 1.0;
return B_ERROR;
}
if (B_OK != pci_irq_init()) {
TRACE(("PCI: IRQ router not available\n"));
} else {
gIrqRouterAvailable = true;
}
pci_init();
pci_print_info();
return B_OK;
} }
status_t static status_t
pci_module_uninit(void) pci_module_register_device(device_node_handle parent)
{ {
TRACE(("PCI: pci_module_uninit\n")); io_resource resources[2] = {
pci_uninit(); { IO_PORT, PCI_CONFIG_ADDRESS, 8 },
return B_OK; {}
};
device_attr attrs[] = {
// info about ourself
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PCI_ROOT_MODULE_NAME }},
// unique connection name
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "PCI" }},
// mark as being a bus
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
// search for device drivers once all devices are detected
//{ PNP_BUS_DEFER_PROBE, B_UINT8_TYPE, { ui8: 1 }},
// don't scan if loaded as we own I/O resources
//{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
{}
};
io_resource_handle resourceHandles[2];
device_node_handle node;
// char *parent_type;
status_t res;
res = gDeviceManager->acquire_io_resources(resources, resourceHandles);
if (res < B_OK)
return res;
return gDeviceManager->register_device(parent, attrs, resourceHandles, &node);
} }
status_t static status_t
pci_module_rescan(void) pci_module_register_child_devices(void *cookie)
{ {
device_node_handle node = cookie;
pci_info device;
int32 i = 0;
while (pci_get_nth_pci_info(i, &device) == B_OK) {
device_attr attrs[] = {
// info about device
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PCI_DEVICE_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string:
"bus: %"PCI_DEVICE_BUS_ITEM
"%, device: %"PCI_DEVICE_DEVICE_ITEM
"%, function: %"PCI_DEVICE_FUNCTION_ITEM"%" }},
// location on PCI bus
{ PCI_DEVICE_BUS_ITEM, B_UINT8_TYPE, { ui8: device.bus }},
{ PCI_DEVICE_DEVICE_ITEM, B_UINT8_TYPE, { ui8: device.device }},
{ PCI_DEVICE_FUNCTION_ITEM, B_UINT8_TYPE, { ui8: device.function }},
// info about the device
{ PCI_DEVICE_VENDOR_ID_ITEM, B_UINT16_TYPE, { ui16: device.vendor_id }},
{ PCI_DEVICE_DEVICE_ID_ITEM, B_UINT16_TYPE, { ui16: device.device_id }},
{ PCI_DEVICE_SUBSYSTEM_ID_ITEM, B_UINT16_TYPE, { ui16: device.u.h0.subsystem_id }},
{ PCI_DEVICE_SUBVENDOR_ID_ITEM, B_UINT16_TYPE, { ui16: device.u.h0.subsystem_vendor_id }},
{ PCI_DEVICE_BASE_CLASS_ID_ITEM, B_UINT8_TYPE, { ui8: device.class_base }},
{ PCI_DEVICE_SUB_CLASS_ID_ITEM, B_UINT8_TYPE, { ui8: device.class_sub }},
{ PCI_DEVICE_API_ID_ITEM, B_UINT8_TYPE, { ui8: device.class_api }},
// consumer specification
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "pci" }},
// ToDo: this is a hack
{ B_DRIVER_DEVICE_TYPE, B_STRING_TYPE, { string: device.class_base == 1 ? "drivers/dev/disk" : "drivers/dev" }},
{ NULL }
};
device_node_handle deviceNode;
gDeviceManager->register_device(node, attrs, NULL, &deviceNode);
// currently, we don't care about loosing devices as we cannot do
// anything about that but want to register remaining devices (if possible)
i++;
}
return B_OK; return B_OK;
} }
int32 static void
pci_module_get_paths(const char ***_bus, const char ***_device)
{
static const char *kBus[] = {"root", NULL};
*_bus = kBus;
*_device = NULL;
}
static uint32
pci_module_read_config(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size)
{
return pci_read_config(bus, device, function, offset, size);
}
static void
pci_module_write_config(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
{
pci_write_config(bus, device, function, offset, size, value);
}
static status_t
pci_module_init(device_node_handle node, void *user_cookie, void **_cookie)
{
*_cookie = node;
return B_OK;
}
static int32
pci_old_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
status_t status;
TRACE(("PCI: pci_module_init\n"));
status = pci_init();
if (status < B_OK)
return status;
pci_print_info();
return B_OK;
}
case B_MODULE_UNINIT:
TRACE(("PCI: pci_module_uninit\n"));
pci_uninit();
return B_OK;
}
return B_BAD_VALUE;
}
static int32
pci_module_std_ops(int32 op, ...) pci_module_std_ops(int32 op, ...)
{ {
switch (op) { switch (op) {
case B_MODULE_INIT: case B_MODULE_INIT:
return pci_module_init(); {
module_info *module;
return get_module(B_PCI_MODULE_NAME, &module);
// this serializes our module initialization
}
case B_MODULE_UNINIT: case B_MODULE_UNINIT:
return pci_module_uninit(); return put_module(B_PCI_MODULE_NAME);
} }
return EINVAL; return B_BAD_VALUE;
} }
struct pci_module_info pci_module = { static struct pci_module_info sOldPCIModule = {
{ {
{ {
B_PCI_MODULE_NAME, B_PCI_MODULE_NAME,
B_KEEP_LOADED, B_KEEP_LOADED,
pci_module_std_ops pci_old_module_std_ops
}, },
pci_module_rescan NULL
}, },
&pci_read_io_8, &pci_read_io_8,
&pci_write_io_8, &pci_write_io_8,
@@ -93,8 +233,40 @@ struct pci_module_info pci_module = {
&pci_ram_address &pci_ram_address
}; };
static struct pci_root_info sPCIModule = {
{
{
{
PCI_ROOT_MODULE_NAME,
0,
pci_module_std_ops
},
pci_module_supports_device,
pci_module_register_device,
pci_module_init,
NULL, // uninit
NULL, // removed
NULL, // cleanup
pci_module_get_paths,
},
pci_module_register_child_devices,
NULL, // rescan bus
},
pci_module_read_config,
pci_module_write_config
};
module_dependency module_dependencies[] = {
{B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager},
{}
};
module_info *modules[] = { module_info *modules[] = {
(module_info *)&pci_module, (module_info *)&sOldPCIModule,
(module_info *)&sPCIModule,
(module_info *)&gPCIDeviceModule,
NULL NULL
}; };
+62 -17
View File
@@ -1,25 +1,46 @@
/*
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2003, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef __PCI_PRIV_H__
#define __PCI_PRIV_H__
#include <KernelExport.h> #include <KernelExport.h>
#include <device_manager.h>
#include <bus/PCI.h>
#ifdef __cplusplus
extern "C" {
#endif
status_t pci_config_init(void); // name of PCI device modules
uint32 pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size); #define PCI_DEVICE_MODULE_NAME "bus_managers/pci/device_v1"
void pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
void * pci_ram_address(const void *physical_address_in_system_memory);
status_t pci_io_init(void); // I/O port for PCI config space address
uint8 pci_read_io_8(int mapped_io_addr); #define PCI_CONFIG_ADDRESS 0xcf8
void pci_write_io_8(int mapped_io_addr, uint8 value); // I/O port for PCI config space data
uint16 pci_read_io_16(int mapped_io_addr); #define PCI_CONFIG_DATA 0xcfc
void pci_write_io_16(int mapped_io_addr, uint16 value);
uint32 pci_read_io_32(int mapped_io_addr); extern device_manager_info *gDeviceManager;
void pci_write_io_32(int mapped_io_addr, uint32 value);
// PCI root.
// apart from being the common parent of all PCI devices, it
// manages access to PCI config space
typedef struct pci_root_info {
bus_module_info info;
// read PCI config space
uint32 (*read_pci_config)(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size);
// write PCI config space
void (*write_pci_config)(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value);
} pci_root_info;
extern pci_device_module_info gPCIDeviceModule;
status_t pci_irq_init(void);
uint8 pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin);
void pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq);
extern spinlock gConfigLock; extern spinlock gConfigLock;
extern int gMaxBusDevices; extern int gMaxBusDevices;
@@ -37,6 +58,30 @@ extern bool gIrqRouterAvailable;
restore_interrupts(cpu_status); \ restore_interrupts(cpu_status); \
} }
#ifdef __cplusplus
extern "C" {
#endif
status_t pci_config_init(void);
uint32 pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
void pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
void *pci_ram_address(const void *physical_address_in_system_memory);
status_t pci_io_init(void);
uint8 pci_read_io_8(int mapped_io_addr);
void pci_write_io_8(int mapped_io_addr, uint8 value);
uint16 pci_read_io_16(int mapped_io_addr);
void pci_write_io_16(int mapped_io_addr, uint16 value);
uint32 pci_read_io_32(int mapped_io_addr);
void pci_write_io_32(int mapped_io_addr, uint32 value);
status_t pci_irq_init(void);
uint8 pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin);
void pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __PCI_PRIV_H__ */
+19 -14
View File
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002-04, Thomas Kurschel. All rights reserved. * Copyright 2002-04, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Part of Open SCSI bus manager Part of Open SCSI bus manager
@@ -35,12 +35,16 @@ static status_t
scsi_bus_raw_init_device(device_node_handle node, scsi_bus_raw_init_device(device_node_handle node,
void *userCookie, void **cookie) void *userCookie, void **cookie)
{ {
device_node_handle parent = pnp->get_parent(node);
bus_raw_info *bus; bus_raw_info *bus;
scsi_bus_interface *interface; scsi_bus_interface *interface;
scsi_bus bus_cookie; scsi_bus bus_cookie;
status_t res = pnp->load_driver(pnp->get_parent(node), NULL, status_t res = pnp->init_driver(parent, NULL,
(driver_module_info **)&interface, (void **)&bus_cookie); (driver_module_info **)&interface, (void **)&bus_cookie);
pnp->put_device_node(parent);
if (res != B_OK) if (res != B_OK)
return res; return res;
@@ -57,11 +61,13 @@ scsi_bus_raw_init_device(device_node_handle node,
static status_t static status_t
scsi_bus_raw_uninit_device(bus_raw_info *bus) scsi_bus_raw_uninit_device(bus_raw_info *bus)
{ {
status_t res; device_node_handle parent = pnp->get_parent(bus->node);
status_t status = pnp->uninit_driver(parent);
res = pnp->unload_driver(pnp->get_parent(bus->node)); pnp->put_device_node(parent);
if (res != B_OK)
return res; if (status != B_OK)
return status;
free(bus); free(bus);
return B_OK; return B_OK;
@@ -86,13 +92,11 @@ scsi_bus_raw_probe(device_node_handle parent)
{ {
device_attr attributes[] = { device_attr attributes[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "bus_raw" }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "bus_raw" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "bus_raw" }},
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }}, { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
{} {}
}; };
@@ -185,9 +189,10 @@ pnp_devfs_driver_info scsi_bus_raw_module = {
std_ops std_ops
}, },
NULL,
scsi_bus_raw_probe,
scsi_bus_raw_init_device, scsi_bus_raw_init_device,
(status_t (*) (void *))scsi_bus_raw_uninit_device, (status_t (*) (void *))scsi_bus_raw_uninit_device,
scsi_bus_raw_probe,
NULL, NULL,
NULL NULL
}, },
+19 -8
View File
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Part of Open SCSI bus manager Part of Open SCSI bus manager
@@ -182,6 +182,7 @@ scsi_destroy_bus(scsi_bus_info *bus)
static status_t static status_t
scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie) scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
{ {
device_node_handle parent;
uint8 path_id; uint8 path_id;
scsi_bus_info *bus; scsi_bus_info *bus;
status_t res; status_t res;
@@ -239,8 +240,13 @@ scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
goto err; goto err;
} }
res = pnp->load_driver(pnp->get_parent(node), bus, parent = pnp->get_parent(node);
res = pnp->init_driver(parent, bus,
(driver_module_info **)&bus->interface, (void **)&bus->sim_cookie); (driver_module_info **)&bus->interface, (void **)&bus->sim_cookie);
pnp->put_device_node(parent);
if (res != B_OK) if (res != B_OK)
goto err; goto err;
@@ -264,7 +270,10 @@ err:
static status_t static status_t
scsi_uninit_bus(scsi_bus_info *bus) scsi_uninit_bus(scsi_bus_info *bus)
{ {
pnp->unload_driver(pnp->get_parent(bus->node)); device_node_handle parent = pnp->get_parent(bus->node);
pnp->uninit_driver(parent);
pnp->put_device_node(parent);
scsi_destroy_bus(bus); scsi_destroy_bus(bus);
return B_OK; return B_OK;
@@ -331,13 +340,15 @@ scsi_bus_interface scsi_bus_module = {
std_ops std_ops
}, },
NULL, // supported devices
NULL, // register node
scsi_init_bus, scsi_init_bus,
(status_t (*) (void *)) scsi_uninit_bus, (status_t (*)(void *))scsi_uninit_bus,
NULL,
NULL NULL
}, },
(status_t (*) (void *)) scsi_scan_bus (status_t (*)(void *))scsi_scan_bus,
NULL
}, },
scsi_inquiry_path, scsi_inquiry_path,
+125 -113
View File
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Part of Open SCSI bus manager Part of Open SCSI bus manager
@@ -22,6 +22,7 @@
#include <stdio.h> #include <stdio.h>
#ifdef USE_FAST_LOG
static fast_log_event_type scsi_device_events[] = { static fast_log_event_type scsi_device_events[] = {
{ ev_scsi_requeue_request, "ev_scsi_requeue_request" }, { ev_scsi_requeue_request, "ev_scsi_requeue_request" },
{ ev_scsi_resubmit_request, "ev_scsi_resubmit_request" }, { ev_scsi_resubmit_request, "ev_scsi_resubmit_request" },
@@ -34,62 +35,72 @@ static fast_log_event_type scsi_device_events[] = {
{ ev_copy_sg_data, "ev_copy_sg_data" }, { ev_copy_sg_data, "ev_copy_sg_data" },
{} {}
}; };
#endif
// free autosense request of device /** free autosense request of device */
static void scsi_free_autosense_request( scsi_device_info *device )
static void
scsi_free_autosense_request(scsi_device_info *device)
{ {
SHOW_FLOW0( 3, "" ); SHOW_FLOW0( 3, "" );
if( device->auto_sense_request != NULL ) { if (device->auto_sense_request != NULL) {
scsi_free_ccb( device->auto_sense_request ); scsi_free_ccb(device->auto_sense_request);
device->auto_sense_request = NULL; device->auto_sense_request = NULL;
} }
if( device->auto_sense_area > 0 ) { if (device->auto_sense_area > 0) {
delete_area( device->auto_sense_area ); delete_area(device->auto_sense_area);
device->auto_sense_area = 0; device->auto_sense_area = 0;
} }
} }
// free all data of device /** free all data of device */
static void scsi_free_device( scsi_device_info *device )
static void
scsi_free_device(scsi_device_info *device)
{ {
SHOW_FLOW0( 3, "" ); SHOW_FLOW0( 3, "" );
scsi_free_emulation_buffer( device );
scsi_free_autosense_request( device );
unregister_kernel_daemon( scsi_dma_buffer_daemon, device );
scsi_dma_buffer_free( &device->dma_buffer ); scsi_free_emulation_buffer(device);
scsi_free_autosense_request(device);
DELETE_BEN( &device->dma_buffer_lock );
delete_sem( device->dma_buffer_owner ); unregister_kernel_daemon(scsi_dma_buffer_daemon, device);
if( device->log != NULL ) scsi_dma_buffer_free(&device->dma_buffer);
fast_log->stop_log( device->log );
DELETE_BEN(&device->dma_buffer_lock);
free( device ); delete_sem(device->dma_buffer_owner);
#ifdef USE_FAST_LOG
if (device->log != NULL)
fast_log->stop_log(device->log);
#endif
free(device);
} }
// copy string src without trailing zero to dst and remove trailing spaces /** copy string src without trailing zero to dst and remove trailing
// size of dst is dst_size, size of src is dst_size-1 * spaces size of dst is dst_size, size of src is dst_size-1
static void beautify_string( char *dst, char *src, int dst_size ) */
static void
beautify_string(char *dst, char *src, int dst_size)
{ {
int i; int i;
memcpy( dst, src, dst_size - 1 ); memcpy(dst, src, dst_size - 1);
for( i = dst_size - 2; i >= 0; --i ) { for (i = dst_size - 2; i >= 0; --i) {
if( dst[i] != ' ' ) if (dst[i] != ' ')
break; break;
} }
dst[i + 1] = 0; dst[i + 1] = 0;
} }
/** register new device */ /** register new device */
@@ -120,41 +131,32 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
char product_rev[sizeof( inquiry_data->product_rev ) + 1]; char product_rev[sizeof( inquiry_data->product_rev ) + 1];
device_attr attrs[] = { device_attr attrs[] = {
// info about driver // info about driver
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_DEVICE_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DEVICE_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_DEVICE_TYPE_NAME }},
// connection // connection
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }}, { SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }}, { SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string:
"target: %"SCSI_DEVICE_TARGET_ID_ITEM "target: %"SCSI_DEVICE_TARGET_ID_ITEM
"%, lun: %"SCSI_DEVICE_TARGET_LUN_ITEM"%" }}, "%, lun: %"SCSI_DEVICE_TARGET_LUN_ITEM"%" }},
// inquiry data (used for both identification and information) // inquiry data (used for both identification and information)
{ SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE, { SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE,
{ raw: { inquiry_data, sizeof( *inquiry_data ) }}}, { raw: { inquiry_data, sizeof( *inquiry_data ) }}},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string:
"inquiry: %" SCSI_DEVICE_INQUIRY_ITEM "%" }},
// some more info for driver loading // some more info for driver loading
{ SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }}, { SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }},
{ SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }}, { SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }},
{ SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }}, { SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }},
{ SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }}, { SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }},
// description of peripheral drivers // description of peripheral drivers
// ToDo: temporary hack to get things started! { B_DRIVER_BUS, B_STRING_TYPE, { string: "scsi" }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "drivers/disk/scsi/scsi_dsk/scsi/device/v1" }}, // ToDo: mapping is missing
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string:
SCSI_PERIPHERAL_DRIVERS_DIR "/"
"type: %" SCSI_DEVICE_TYPE_ITEM "%|"
", vendor: %" SCSI_DEVICE_VENDOR_ITEM "%|"
", product: %" SCSI_DEVICE_PRODUCT_ITEM "%|"
", revision: %" SCSI_DEVICE_REVISION_ITEM "%" }},
// extra restriction of maximum number of blocks per transfer // extra restriction of maximum number of blocks per transfer
{ BLKDEV_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }}, { BLKDEV_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
// atapi emulation // atapi emulation
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }}, { SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
// manual autosense // manual autosense
@@ -179,19 +181,19 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
// create data structure for a device // create data structure for a device
static scsi_device_info * static scsi_device_info *
scsi_create_device( device_node_handle node, scsi_bus_info *bus, scsi_create_device(device_node_handle node, scsi_bus_info *bus,
int target_id, int target_lun) int target_id, int target_lun)
{ {
scsi_device_info *device; scsi_device_info *device;
SHOW_FLOW0( 3, "" ); SHOW_FLOW0( 3, "" );
device = (scsi_device_info *)malloc( sizeof( *device )); device = (scsi_device_info *)malloc(sizeof(*device));
if( device == NULL ) if (device == NULL)
return NULL; return NULL;
memset( device, 0, sizeof( *device )); memset(device, 0, sizeof(*device));
device->lock_count = device->blocked[0] = device->blocked[1] = 0; device->lock_count = device->blocked[0] = device->blocked[1] = 0;
device->sim_overflow = 0; device->sim_overflow = 0;
device->queued_reqs = NULL; device->queued_reqs = NULL;
@@ -200,31 +202,35 @@ scsi_create_device( device_node_handle node, scsi_bus_info *bus,
device->target_lun = target_lun; device->target_lun = target_lun;
device->valid = true; device->valid = true;
device->node = node; device->node = node;
scsi_dma_buffer_init( &device->dma_buffer );
if( INIT_BEN( &device->dma_buffer_lock, "dma_buffer" ) < 0 ) scsi_dma_buffer_init(&device->dma_buffer);
if (INIT_BEN(&device->dma_buffer_lock, "dma_buffer") < 0)
goto err; goto err;
device->dma_buffer_owner = create_sem( 1, "dma_buffer" ); device->dma_buffer_owner = create_sem(1, "dma_buffer");
if( device->dma_buffer_owner < 0 ) if (device->dma_buffer_owner < 0)
goto err2; goto err2;
register_kernel_daemon( scsi_dma_buffer_daemon, device, 5 * 10 ); register_kernel_daemon(scsi_dma_buffer_daemon, device, 5 * 10);
return device; return device;
err2: err2:
DELETE_BEN( &device->dma_buffer_lock ); DELETE_BEN(&device->dma_buffer_lock);
err: err:
free( device ); free(device);
return NULL; return NULL;
} }
// prepare autosense request.
// this cannot be done on demand but during init as we may /** prepare autosense request.
// have run out of ccbs when we need it * this cannot be done on demand but during init as we may
static status_t scsi_create_autosense_request( scsi_device_info *device ) * have run out of ccbs when we need it
*/
static status_t
scsi_create_autosense_request(scsi_device_info *device)
{ {
scsi_ccb *request; scsi_ccb *request;
char *buffer; char *buffer;
@@ -232,28 +238,28 @@ static status_t scsi_create_autosense_request( scsi_device_info *device )
size_t total_size; size_t total_size;
SHOW_FLOW0( 3, "" ); SHOW_FLOW0( 3, "" );
device->auto_sense_request = request = scsi_alloc_ccb( device ); device->auto_sense_request = request = scsi_alloc_ccb(device);
if( device->auto_sense_request == NULL ) if (device->auto_sense_request == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
total_size = SCSI_MAX_SENSE_SIZE + sizeof( physical_entry ); total_size = SCSI_MAX_SENSE_SIZE + sizeof(physical_entry);
total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
// allocate buffer for space sense data and S/G list // allocate buffer for space sense data and S/G list
device->auto_sense_area = create_area( "auto_sense", device->auto_sense_area = create_area("auto_sense",
(void **)&buffer, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 0 ); (void **)&buffer, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 0);
if( device->auto_sense_area < 0 ) if (device->auto_sense_area < 0)
goto err; goto err;
request->data = buffer; request->data = buffer;
request->data_len = SCSI_MAX_SENSE_SIZE; request->data_len = SCSI_MAX_SENSE_SIZE;
request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE); request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE);
request->sg_cnt = 1; request->sg_cnt = 1;
get_memory_map( buffer, SCSI_MAX_SENSE_SIZE, get_memory_map(buffer, SCSI_MAX_SENSE_SIZE,
(physical_entry *)request->sg_list, 1 ); (physical_entry *)request->sg_list, 1);
// disable auto-autosense, just in case; // disable auto-autosense, just in case;
// make sure no other request overtakes sense request; // make sure no other request overtakes sense request;
// buffer is/must be DMA safe as we cannot risk trouble with // buffer is/must be DMA safe as we cannot risk trouble with
@@ -262,15 +268,15 @@ static status_t scsi_create_autosense_request( scsi_device_info *device )
SCSI_ORDERED_QTAG | SCSI_DMA_SAFE; SCSI_ORDERED_QTAG | SCSI_DMA_SAFE;
cmd = (scsi_cmd_request_sense *)request->cdb; cmd = (scsi_cmd_request_sense *)request->cdb;
request->cdb_len = sizeof( *cmd ); request->cdb_len = sizeof(*cmd);
memset( cmd, 0, sizeof( *cmd )); memset(cmd, 0, sizeof(*cmd));
cmd->opcode = SCSI_OP_REQUEST_SENSE; cmd->opcode = SCSI_OP_REQUEST_SENSE;
cmd->LUN = device->target_lun; cmd->LUN = device->target_lun;
cmd->alloc_length = SCSI_MAX_SENSE_SIZE; cmd->alloc_length = SCSI_MAX_SENSE_SIZE;
return B_OK; return B_OK;
err: err:
scsi_free_ccb(request); scsi_free_ccb(request);
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -282,6 +288,7 @@ err:
static status_t static status_t
scsi_init_device(device_node_handle node, void *user_cookie, void **cookie) scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
{ {
device_node_handle parent = pnp->get_parent(node);
scsi_res_inquiry *inquiry_data = NULL; scsi_res_inquiry *inquiry_data = NULL;
uint8 target_id, target_lun, path_id; uint8 target_id, target_lun, path_id;
scsi_bus_info *bus; scsi_bus_info *bus;
@@ -301,13 +308,13 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
(void **)&inquiry_data, &inquiry_data_len, false) != B_OK (void **)&inquiry_data, &inquiry_data_len, false) != B_OK
|| inquiry_data_len != sizeof(*inquiry_data)) { || inquiry_data_len != sizeof(*inquiry_data)) {
res = B_ERROR; res = B_ERROR;
goto err3; goto err1;
} }
res = pnp->load_driver(pnp->get_parent(node), NULL, &bus_interface, res = pnp->init_driver(parent, NULL, &bus_interface,
(void **)&bus); (void **)&bus);
if (res != B_OK) if (res != B_OK)
goto err3; goto err1;
device = scsi_create_device(node, bus, target_id, target_lun); device = scsi_create_device(node, bus, target_id, target_lun);
if (device == NULL) { if (device == NULL) {
@@ -322,11 +329,13 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
sprintf(device->name, "scsi_device %u:%u:%u", path_id, target_id, target_lun); sprintf(device->name, "scsi_device %u:%u:%u", path_id, target_id, target_lun);
#ifdef USE_FAST_LOG
device->log = fast_log->start_log(device->name, scsi_device_events); device->log = fast_log->start_log(device->name, scsi_device_events);
if (device->log == NULL) { if (device->log == NULL) {
res = B_NO_MEMORY; res = B_NO_MEMORY;
goto err; goto err3;
} }
#endif
device->inquiry_data = *inquiry_data; device->inquiry_data = *inquiry_data;
@@ -353,14 +362,14 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
if (device->manual_autosense) { if (device->manual_autosense) {
if (scsi_create_autosense_request(device) != B_OK) { if (scsi_create_autosense_request(device) != B_OK) {
res = B_NO_MEMORY; res = B_NO_MEMORY;
goto err; goto err3;
} }
} }
// if this is an ATAPI device, we need an emulation buffer // if this is an ATAPI device, we need an emulation buffer
if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) { if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) {
res = B_NO_MEMORY; res = B_NO_MEMORY;
goto err; goto err3;
} }
memset(device->emulation_map, 0, sizeof(device->emulation_map)); memset(device->emulation_map, 0, sizeof(device->emulation_map));
@@ -378,13 +387,13 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
*cookie = device; *cookie = device;
return B_OK; return B_OK;
err: err3:
scsi_free_device(device); scsi_free_device(device);
err2: err2:
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(parent);
err3: err1:
if (inquiry_data != NULL) pnp->put_device_node(parent);
free(inquiry_data); free(inquiry_data);
return res; return res;
} }
@@ -392,14 +401,15 @@ err3:
static status_t static status_t
scsi_uninit_device(scsi_device_info *device) scsi_uninit_device(scsi_device_info *device)
{ {
device_node_handle node = device->node; device_node_handle parent = pnp->get_parent(device->node);
SHOW_FLOW0(3, ""); SHOW_FLOW0(3, "");
scsi_free_device(device); scsi_free_device(device);
// must unload parent at last as scsi_free_device access it // must unload parent at last as scsi_free_device access it
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(parent);
pnp->put_device_node(parent);
return B_OK; return B_OK;
} }
@@ -424,11 +434,10 @@ scsi_device_removed(device_node_handle node, scsi_device_info *device)
*/ */
status_t status_t
scsi_force_get_device( scsi_bus_info *bus, uchar target_id, scsi_force_get_device(scsi_bus_info *bus, uchar target_id,
uchar target_lun, scsi_device_info **res_device) uchar target_lun, scsi_device_info **res_device)
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_DEVICE_TYPE_NAME }},
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }}, { SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }}, { SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
{ NULL } { NULL }
@@ -443,15 +452,17 @@ scsi_force_get_device( scsi_bus_info *bus, uchar target_id,
// very important: only one can use a forced device to avoid double detection // very important: only one can use a forced device to avoid double detection
acquire_sem(bus->scan_lun_lock); acquire_sem(bus->scan_lun_lock);
// check whether device registered already // check whether device registered already
node = pnp->find_device(bus->node, attrs); node = NULL;
pnp->get_next_child_device(bus->node, &node, attrs);
SHOW_FLOW(3, "%p", node); SHOW_FLOW(3, "%p", node);
if (node != NULL) { if (node != NULL) {
// there is one - get it // there is one - get it
res = pnp->load_driver(node, NULL, &driver_interface, res = pnp->init_driver(node, NULL, &driver_interface,
(void **)&device); (void **)&device);
pnp->put_device_node(node);
} else { } else {
// device doesn't exist yet - create a temporary one // device doesn't exist yet - create a temporary one
device = scsi_create_device(NULL, bus, target_id, target_lun); device = scsi_create_device(NULL, bus, target_id, target_lun);
@@ -483,7 +494,7 @@ scsi_put_forced_device(scsi_device_info *device)
if (device->node != NULL) if (device->node != NULL)
// device is registered // device is registered
pnp->unload_driver(device->node); pnp->uninit_driver(device->node);
else else
// device is temporary // device is temporary
scsi_free_device(device); scsi_free_device(device);
@@ -534,9 +545,10 @@ scsi_device_interface scsi_device_module = {
std_ops std_ops
}, },
NULL, // supported devices
NULL, // register node
scsi_init_device, scsi_init_device,
(status_t (*)(void *)) scsi_uninit_device, (status_t (*)(void *)) scsi_uninit_device,
NULL,
(void (*)(device_node_handle, void *)) scsi_device_removed (void (*)(device_node_handle, void *)) scsi_device_removed
}, },
+4 -7
View File
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Part of Open SCSI bus manager Part of Open SCSI bus manager
@@ -14,16 +14,13 @@
locked_pool_interface *locked_pool; locked_pool_interface *locked_pool;
device_manager_info *pnp; device_manager_info *pnp;
fast_log_info *fast_log;
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool }, { LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
{ FAST_LOG_MODULE_NAME, (module_info **)&fast_log },
{} {}
}; };
_EXPORT
module_info *modules[] = { module_info *modules[] = {
(module_info *)&scsi_for_sim_module, (module_info *)&scsi_for_sim_module,
(module_info *)&scsi_bus_module, (module_info *)&scsi_bus_module,
@@ -200,8 +200,10 @@ typedef struct scsi_device_info {
benaphore dma_buffer_lock; // lock between DMA buffer user and clean-up daemon benaphore dma_buffer_lock; // lock between DMA buffer user and clean-up daemon
sem_id dma_buffer_owner; // to be acquired before using DMA buffer sem_id dma_buffer_owner; // to be acquired before using DMA buffer
dma_buffer dma_buffer; // DMA buffer dma_buffer dma_buffer; // DMA buffer
#ifdef USE_FAST_LOG
fast_log_handle log; // fast log connection fast_log_handle log; // fast log connection
#endif
char name[30]; // name for fast log entries char name[30]; // name for fast log entries
// buffer used for emulating SCSI commands // buffer used for emulating SCSI commands
@@ -27,33 +27,20 @@
static status_t static status_t
scsi_controller_added(device_node_handle parent) scsi_controller_added(device_node_handle parent)
{ {
char *controller_name;
int path_id; int path_id;
char *str, *controller_name;
SHOW_FLOW0(4, ""); SHOW_FLOW0(4, "");
if (pnp->get_attr_string(parent, PNP_DRIVER_TYPE, &str, false) != B_OK)
return B_ERROR;
if (strcmp(str, SCSI_SIM_TYPE_NAME) != 0) {
free(str);
return B_ERROR;
}
free(str);
if (pnp->get_attr_string(parent, SCSI_DESCRIPTION_CONTROLLER_NAME, if (pnp->get_attr_string(parent, SCSI_DESCRIPTION_CONTROLLER_NAME,
&controller_name, false) != B_OK) { &controller_name, false) != B_OK) {
pnp->get_attr_string(parent, PNP_DRIVER_DRIVER, &str, false); dprintf("scsi: ignored controller - controller name missing\n");
SHOW_ERROR(0, "Ignored controller managed by %s - controller name missing",
str);
return B_ERROR; return B_ERROR;
} }
path_id = pnp->create_id(SCSI_PATHID_GENERATOR); path_id = pnp->create_id(SCSI_PATHID_GENERATOR);
if (path_id < 0) { if (path_id < 0) {
SHOW_ERROR(0, "Cannot register SCSI controller %s - out of path IDs", dprintf("scsi: Cannot register SCSI controller %s - out of path IDs\n",
controller_name); controller_name);
free(controller_name); free(controller_name);
return B_ERROR; return B_ERROR;
@@ -64,13 +51,10 @@ scsi_controller_added(device_node_handle parent)
{ {
device_attr attrs[] = { device_attr attrs[] = {
// general information // general information
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_BUS_TYPE_NAME }},
// we are a bus // we are a bus
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }}, { PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
// search for peripheral drivers after bus is fully scanned
{ PNP_BUS_DEFER_PROBE, B_UINT8_TYPE, {ui8: 1 }},
// remember who we are // remember who we are
// (could use the controller name, but probably some software would choke) // (could use the controller name, but probably some software would choke)
@@ -81,7 +65,7 @@ scsi_controller_added(device_node_handle parent)
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }}, { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }},
// tell internal bus raw driver to register bus' device in devfs // tell internal bus raw driver to register bus' device in devfs
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
{ NULL, 0 } { NULL, 0 }
}; };
@@ -115,9 +99,10 @@ scsi_for_sim_interface scsi_for_sim_module =
std_ops std_ops
}, },
NULL, // supported devices
scsi_controller_added,
NULL, NULL,
NULL, NULL,
scsi_controller_added,
NULL NULL
}, },
@@ -23,7 +23,7 @@
#include "wrapper.h" #include "wrapper.h"
#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/" PCI_DEVICE_TYPE_NAME #define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/device_v1"
#define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1" #define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1"
#define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller" #define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller"
@@ -164,6 +164,39 @@ probe_controller(device_node_handle parent)
} }
static float
supports_device(device_node_handle parent, bool *_noConnection)
{
char *bus;
uint8 baseClass, subClass;
// make sure parent is an PCI IDE mass storage host adapter device node
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false) != B_OK
|| pnp->get_attr_uint8(parent, PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) != B_OK
|| pnp->get_attr_uint8(parent, PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) != B_OK)
return B_ERROR;
if (strcmp(bus, "pci") || baseClass != PCI_mass_storage || subClass != PCI_ide) {
free(bus);
return 0.0;
}
free(bus);
return 0.3;
}
static void
get_paths(const char ***_bus, const char ***_device)
{
static const char *kBus[] = { "pci", NULL };
static const char *kDevice[] = { "drivers/dev/disk/ide", NULL };
*_bus = kBus;
*_device = kDevice;
}
static status_t static status_t
module_std_ops(int32 op, ...) module_std_ops(int32 op, ...)
{ {
@@ -180,7 +213,7 @@ module_std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter }, { IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
{} {}
}; };
@@ -195,10 +228,13 @@ static ide_controller_interface channel_interface = {
module_std_ops module_std_ops
}, },
(status_t (*)( device_node_handle , void *, void ** )) init_channel, NULL, // supports device
(status_t (*)( void * )) uninit_channel, NULL, // register device
NULL, (status_t (*)(device_node_handle, void *, void **))init_channel,
(void (*)( device_node_handle , void * )) channel_removed (status_t (*)(void *))uninit_channel,
(void (*)(device_node_handle, void *))channel_removed,
NULL, // cleanup
NULL, // get_paths
}, },
(status_t (*)(ide_channel_cookie, (status_t (*)(ide_channel_cookie,
@@ -226,17 +262,17 @@ static driver_module_info controller_interface = {
module_std_ops module_std_ops
}, },
(status_t (*)( device_node_handle, void *, void ** )) init_controller, supports_device,
(status_t (*)( void * )) uninit_controller,
probe_controller, probe_controller,
(void (*)( device_node_handle, void * )) controller_removed (status_t (*)(device_node_handle, void *, void **)) init_controller,
(status_t (*)(void *)) uninit_controller,
(void (*)(device_node_handle, void *)) controller_removed,
NULL, // cleanup
get_paths,
}; };
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = { module_info *modules[] = {
(module_info *)&controller_interface, (module_info *)&controller_interface,
(module_info *)&channel_interface, (module_info *)&channel_interface,
NULL NULL
}; };
#endif
+53 -23
View File
@@ -30,7 +30,7 @@
#include "wrapper.h" #include "wrapper.h"
#define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/"ISA_DEVICE_TYPE_NAME #define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/device_v1"
// private node item: // private node item:
// io address of command block // io address of command block
@@ -223,6 +223,27 @@ finish_dma(void *channel)
} }
static float
supports_device(device_node_handle parent, bool *_noConnection)
{
char *bus;
// make sure parent is really the ISA bus manager
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
return B_ERROR;
if (strcmp(bus, "isa")) {
free(bus);
return 0.0;
}
// ToDo: check I/O resources for availability?
free(bus);
return 0.6;
}
static status_t static status_t
init_channel(device_node_handle node, ide_channel ide_channel, channel_info **cookie) init_channel(device_node_handle node, ide_channel ide_channel, channel_info **cookie)
{ {
@@ -239,7 +260,7 @@ init_channel(device_node_handle node, ide_channel ide_channel, channel_info **co
|| pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK) || pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK)
return B_ERROR; return B_ERROR;
if (pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&isa, &dummy) != B_OK) if (pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&isa, &dummy) != B_OK)
return B_ERROR; return B_ERROR;
channel = (channel_info *)malloc(sizeof(channel_info)); channel = (channel_info *)malloc(sizeof(channel_info));
@@ -275,7 +296,7 @@ err:
free(channel); free(channel);
err0: err0:
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(pnp->get_parent(node));
return res; return res;
} }
@@ -293,7 +314,7 @@ uninit_channel(channel_info *channel)
remove_io_interrupt_handler(channel->intnum, inthand, channel); remove_io_interrupt_handler(channel->intnum, inthand, channel);
pnp->unload_driver(pnp->get_parent(channel->node)); pnp->uninit_driver(pnp->get_parent(channel->node));
free(channel); free(channel);
@@ -301,20 +322,18 @@ uninit_channel(channel_info *channel)
} }
// publish node of ide channel /** publish node of an ide channel */
static status_t static status_t
publish_channel(device_node_handle parent, io_resource_handle *resources, uint16 command_block_base, publish_channel(device_node_handle parent, io_resource_handle *resources,
uint16 control_block_base, uint8 intnum, const char *name) uint16 command_block_base, uint16 control_block_base, uint8 intnum,
const char *name)
{ {
device_attr attrs[] = { device_attr attrs[] = {
// info about ourself and our consumer // info about ourself and our consumer
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "ide_isa" }},
// don't scan if loaded as we own I/O resources
{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
// properties of this controller for ide bus manager // properties of this controller for ide bus manager
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }}, { IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
@@ -363,16 +382,16 @@ probe_channel(device_node_handle parent,
// we assume that every modern PC has an IDE controller, so no // we assume that every modern PC has an IDE controller, so no
// further testing is done (well - I don't really know how to detect the // further testing is done (well - I don't really know how to detect the
// controll, but who cares ;) // controller, but who cares ;)
return publish_channel(parent, resource_handles, command_block_base, return publish_channel(parent, resource_handles, command_block_base,
control_block_base, intnum, name); control_block_base, intnum, name);
} }
static status_t static status_t
scan_parent(device_node_handle node) register_device(device_node_handle node)
{ {
SHOW_FLOW0( 3, "" ); SHOW_FLOW0(3, "");
// our parent device is the isa bus and all device drivers are Universal, // our parent device is the isa bus and all device drivers are Universal,
// so the pnp_manager tries each ISA driver in turn // so the pnp_manager tries each ISA driver in turn
@@ -386,7 +405,7 @@ scan_parent(device_node_handle node)
static void static void
channel_removed(device_node_handle node, channel_info *channel) channel_removed(device_node_handle node, channel_info *channel)
{ {
SHOW_FLOW0( 3, "" ); SHOW_FLOW0(3, "");
if (channel != NULL) if (channel != NULL)
// disable access instantly // disable access instantly
@@ -396,6 +415,17 @@ channel_removed(device_node_handle node, channel_info *channel)
} }
static void
get_paths(const char ***_bus, const char ***_device)
{
static const char *kBus[] = {"isa", NULL};
static const char *kDevice[] = {"drivers/dev/disk/ide", NULL};
*_bus = kBus;
*_device = kDevice;
}
static status_t static status_t
std_ops(int32 op, ...) std_ops(int32 op, ...)
{ {
@@ -412,7 +442,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -425,10 +455,13 @@ ide_controller_interface isa_controller_interface = {
std_ops std_ops
}, },
supports_device,
register_device,
(status_t (*)(device_node_handle, void *, void **)) init_channel, (status_t (*)(device_node_handle, void *, void **)) init_channel,
(status_t (*)(void *)) uninit_channel, (status_t (*)(void *)) uninit_channel,
scan_parent, (void (*)(device_node_handle, void *)) channel_removed,
(void (*)(device_node_handle, void *)) channel_removed NULL, // cleanup
get_paths
}, },
(status_t (*)(ide_channel_cookie, (status_t (*)(ide_channel_cookie,
@@ -448,10 +481,7 @@ ide_controller_interface isa_controller_interface = {
(status_t (*)(ide_channel_cookie)) &finish_dma, (status_t (*)(ide_channel_cookie)) &finish_dma,
}; };
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = { module_info *modules[] = {
(module_info *)&isa_controller_interface, (module_info *)&isa_controller_interface,
NULL NULL
}; };
#endif
@@ -22,11 +22,9 @@
#include "wrapper.h" #include "wrapper.h"
#define PROMISE_TX2_CONTROLLER_MODULE_NAME "busses/ide/promise_tx2/" PCI_DEVICE_TYPE_NAME #define PROMISE_TX2_CONTROLLER_MODULE_NAME "busses/ide/promise_tx2/device_v1"
#define PROMISE_TX2_CHANNEL_MODULE_NAME "busses/ide/promise_tx2/channel/v1" #define PROMISE_TX2_CHANNEL_MODULE_NAME "busses/ide/promise_tx2/channel/v1"
#define PROMISE_TX2_CONTROLLER_TYPE_NAME "promise tx2 controller"
static ide_for_controller_interface *ide; static ide_for_controller_interface *ide;
static ide_adapter_interface *ide_adapter; static ide_adapter_interface *ide_adapter;
@@ -190,10 +188,7 @@ publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intn
{ {
device_attr attrs[] = { device_attr attrs[] = {
// info about ourself and our consumer // info about ourself and our consumer
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_TYPE_NAME }},
// don't scan if loaded as we own I/O resources
{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
// properties of this controller for ide bus manager // properties of this controller for ide bus manager
// there are always max. 2 devices // there are always max. 2 devices
@@ -273,7 +268,7 @@ probe_controller(device_node_handle parent)
SHOW_FLOW0(3, ""); SHOW_FLOW0(3, "");
if (pnp->load_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK) if (pnp->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
return B_ERROR; return B_ERROR;
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4); command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4);
@@ -297,12 +292,12 @@ probe_controller(device_node_handle parent)
command_block_base[1], control_block_base[1], bus_master_base, intnum, false, command_block_base[1], control_block_base[1], bus_master_base, intnum, false,
"Secondary Channel", &channels[1], false); "Secondary Channel", &channels[1], false);
pnp->unload_driver(parent); pnp->uninit_driver(parent);
return B_OK; return B_OK;
err: err:
pnp->unload_driver(parent); pnp->uninit_driver(parent);
return res; return res;
} }
@@ -323,7 +318,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter }, { IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
{} {}
}; };
@@ -338,9 +333,10 @@ static ide_controller_interface channel_interface = {
std_ops std_ops
}, },
NULL, // supported devices
NULL,
(status_t (*)( device_node_handle , void *, void ** )) init_channel, (status_t (*)( device_node_handle , void *, void ** )) init_channel,
(status_t (*)( void * )) uninit_channel, (status_t (*)( void * )) uninit_channel,
NULL,
(void (*)( device_node_handle , void * )) channel_removed (void (*)( device_node_handle , void * )) channel_removed
}, },
@@ -369,17 +365,15 @@ static driver_module_info controller_interface = {
std_ops std_ops
}, },
NULL,
probe_controller,
(status_t (*)(device_node_handle, void *, void **)) init_controller, (status_t (*)(device_node_handle, void *, void **)) init_controller,
(status_t (*)(void *)) uninit_controller, (status_t (*)(void *)) uninit_controller,
probe_controller,
(void (*)(device_node_handle, void *)) controller_removed (void (*)(device_node_handle, void *)) controller_removed
}; };
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = { module_info *modules[] = {
(module_info *)&controller_interface, (module_info *)&controller_interface,
(module_info *)&channel_interface, (module_info *)&channel_interface,
NULL NULL
}; };
#endif
+8 -21
View File
@@ -157,7 +157,7 @@ raw_init_device(device_node_handle node, void *user_cookie, void **cookie)
device->node = node; device->node = node;
// register it everywhere // register it everywhere
res = pnp->load_driver(pnp->get_parent(node), NULL, res = pnp->init_driver(pnp->get_parent(node), NULL,
(driver_module_info **)&device->scsi, (void **)&device->scsi_device); (driver_module_info **)&device->scsi, (void **)&device->scsi_device);
if (res != B_OK) if (res != B_OK)
goto err; goto err;
@@ -176,7 +176,7 @@ err:
static status_t static status_t
raw_uninit_device(raw_device_info *device) raw_uninit_device(raw_device_info *device)
{ {
pnp->unload_driver(pnp->get_parent(device->node)); pnp->uninit_driver(pnp->get_parent(device->node));
free(device); free(device);
return B_OK; return B_OK;
@@ -192,21 +192,9 @@ raw_device_added(device_node_handle node)
{ {
uint8 path_id, target_id, target_lun; uint8 path_id, target_id, target_lun;
char name[100]; char name[100];
char *str;
SHOW_FLOW0(3, ""); SHOW_FLOW0(3, "");
// make sure we can handle this parent device
if (pnp->get_attr_string(node, PNP_DRIVER_TYPE, &str, false) != B_OK)
return B_ERROR;
if (strcmp(str, SCSI_DEVICE_TYPE_NAME) != 0) {
free(str);
return B_ERROR;
}
free(str);
// compose name // compose name
if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK
|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK || pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK
@@ -221,18 +209,16 @@ raw_device_added(device_node_handle node)
// ready to register // ready to register
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }},
// default connection is used by peripheral drivers, and as we don't // default connection is used by peripheral drivers, and as we don't
// want to kick them out, we use concurrent "raw" connection // want to kick them out, we use concurrent "raw" connection
// (btw: this shows nicely that something goes wrong: one device // (btw: this shows nicely that something goes wrong: one device
// and two drivers means begging for trouble) // and two drivers means begging for trouble)
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "raw" }},
// we want devfs on top of us // we want devfs on top of us (who wouldn't?)
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
// tell which name we want to have in devfs // tell which name we want to have in devfs
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }}, { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
{ NULL } { NULL }
@@ -258,7 +244,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -270,9 +256,10 @@ pnp_devfs_driver_info scsi_raw_module = {
std_ops std_ops
}, },
NULL,
raw_device_added,
raw_init_device, raw_init_device,
(status_t (*) (void *))raw_uninit_device, (status_t (*) (void *))raw_uninit_device,
raw_device_added,
NULL NULL
}, },
@@ -50,7 +50,7 @@ cd_init_device(device_node_handle node, void *user_cookie, void **cookie)
// we don't verify type - in worst case, the device doesn't work // we don't verify type - in worst case, the device doesn't work
// register it everywhere // register it everywhere
res = pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi, res = pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
(void **)&device->scsi_device); (void **)&device->scsi_device);
if (res != B_OK) if (res != B_OK)
goto err2; goto err2;
@@ -71,7 +71,7 @@ cd_init_device(device_node_handle node, void *user_cookie, void **cookie)
return B_OK; return B_OK;
err3: err3:
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(pnp->get_parent(node));
err2: err2:
err1: err1:
free(device); free(device);
@@ -83,7 +83,7 @@ status_t
cd_uninit_device(cd_device_info *device) cd_uninit_device(cd_device_info *device)
{ {
scsi_periph->unregister_device(device->scsi_periph_device); scsi_periph->unregister_device(device->scsi_periph_device);
pnp->unload_driver(pnp->get_parent(device->node)); pnp->uninit_driver(pnp->get_parent(device->node));
free(device); free(device);
return B_OK; return B_OK;
@@ -98,7 +98,6 @@ cd_uninit_device(cd_device_info *device)
status_t status_t
cd_device_added(device_node_handle node) cd_device_added(device_node_handle node)
{ {
char *str = NULL;
uint8 device_type; uint8 device_type;
scsi_res_inquiry *device_inquiry = NULL; scsi_res_inquiry *device_inquiry = NULL;
size_t inquiry_len; size_t inquiry_len;
@@ -107,11 +106,6 @@ cd_device_added(device_node_handle node)
SHOW_FLOW0( 3, "" ); SHOW_FLOW0( 3, "" );
// make sure we can handle this parent device
if( pnp->get_attr_string( node, PNP_DRIVER_TYPE, &str, false ) != B_OK ||
strcmp( str, SCSI_DEVICE_TYPE_NAME ) != 0 )
goto err;
// check whether it's really a CD-ROM or a WORM // check whether it's really a CD-ROM or a WORM
if( pnp->get_attr_uint8( node, SCSI_DEVICE_TYPE_ITEM, if( pnp->get_attr_uint8( node, SCSI_DEVICE_TYPE_ITEM,
&device_type, true ) != B_OK || &device_type, true ) != B_OK ||
@@ -145,11 +139,10 @@ cd_device_added(device_node_handle node)
// ready to register // ready to register
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_CD_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_CD_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: BLKDEV_TYPE_NAME }}, // we always want blkman on top of us
// we always want blkdev on top of us { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }}, // tell blkman whether the device is removable
// tell blkdev whether the device is removable
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }}, { "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
// tell which name we want to have in devfs // tell which name we want to have in devfs
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }}, { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
@@ -162,14 +155,12 @@ cd_device_added(device_node_handle node)
res = pnp->register_device(node, attrs, NULL, &node); res = pnp->register_device(node, attrs, NULL, &node);
free(name); free(name);
free(str);
free(device_inquiry); free(device_inquiry);
return res; return res;
} }
err: err:
free(str);
free(device_inquiry); free(device_inquiry);
return B_ERROR; return B_ERROR;
File diff suppressed because it is too large Load Diff
@@ -41,7 +41,7 @@ das_init_device(device_node_handle node, void *user_cookie, void **cookie)
goto err1; goto err1;
// register it everywhere // register it everywhere
res = pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi, res = pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
(void **)&device->scsi_device); (void **)&device->scsi_device);
if (res != B_OK) if (res != B_OK)
goto err2; goto err2;
@@ -71,7 +71,7 @@ das_init_device(device_node_handle node, void *user_cookie, void **cookie)
err4: err4:
scsi_periph->unregister_device(device->scsi_periph_device); scsi_periph->unregister_device(device->scsi_periph_device);
err3: err3:
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(pnp->get_parent(node));
err2: err2:
err1: err1:
free(device); free(device);
@@ -83,7 +83,7 @@ status_t
das_uninit_device(das_device_info *device) das_uninit_device(das_device_info *device)
{ {
scsi_periph->unregister_device(device->scsi_periph_device); scsi_periph->unregister_device(device->scsi_periph_device);
pnp->unload_driver(pnp->get_parent(device->node)); pnp->uninit_driver(pnp->get_parent(device->node));
free(device); free(device);
return B_OK; return B_OK;
@@ -98,18 +98,12 @@ das_uninit_device(das_device_info *device)
status_t status_t
das_device_added(device_node_handle node) das_device_added(device_node_handle node)
{ {
char *str = NULL;
scsi_res_inquiry *device_inquiry = NULL; scsi_res_inquiry *device_inquiry = NULL;
uint8 device_type; uint8 device_type;
size_t inquiry_len; size_t inquiry_len;
char *name; char *name;
uint32 max_blocks; uint32 max_blocks;
// make sure we can handle this parent device
if (pnp->get_attr_string(node, PNP_DRIVER_TYPE, &str, false) != B_OK
|| strcmp(str, SCSI_DEVICE_TYPE_NAME) != 0)
goto err;
// check whether it's really a Direct Access Device // check whether it's really a Direct Access Device
if (pnp->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK if (pnp->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK
|| device_type != scsi_dev_direct_access) || device_type != scsi_dev_direct_access)
@@ -141,11 +135,10 @@ das_device_added(device_node_handle node)
// ready to register // ready to register
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: BLKDEV_TYPE_NAME }}, // we always want blkman on top of us
// we always want blkdev on top of us { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }}, // tell blkman whether the device is removable
// tell blkdev whether the device is removable
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }}, { "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
// tell which name we want to have in devfs // tell which name we want to have in devfs
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }}, { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
@@ -159,14 +152,12 @@ das_device_added(device_node_handle node)
status_t res = pnp->register_device(node, attrs, NULL, &node); status_t res = pnp->register_device(node, attrs, NULL, &node);
free(name); free(name);
free(str);
free(device_inquiry); free(device_inquiry);
return res; return res;
} }
err: err:
free(str);
free(device_inquiry); free(device_inquiry);
return B_ERROR; return B_ERROR;
@@ -16,7 +16,9 @@
#include "scsi_dsk_int.h" #include "scsi_dsk_int.h"
#include <scsi.h> #include <scsi.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
extern blkdev_interface das_interface; extern blkdev_interface das_interface;
@@ -222,6 +224,37 @@ das_ioctl(das_handle_info *handle, int op, void *buf, size_t len)
} }
static float
das_supports_device(device_node_handle parent, bool *_noConnection)
{
char *bus;
// make sure parent is really the SCSI bus manager
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
return B_ERROR;
if (strcmp(bus, "scsi")) {
free(bus);
return 0.0;
}
// ToDo: check SCSI device type! (must be "disk")
free(bus);
return 0.6;
}
static void
das_get_paths(const char ***_bus, const char ***_device)
{
static const char *kBus[] = { "scsi", NULL };
*_bus = kBus;
*_device = NULL;
}
static status_t static status_t
std_ops(int32 op, ...) std_ops(int32 op, ...)
{ {
@@ -239,7 +272,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ SCSI_PERIPH_MODULE_NAME, (module_info **)&scsi_periph }, { SCSI_PERIPH_MODULE_NAME, (module_info **)&scsi_periph },
{ BLKMAN_FOR_DRIVER_MODULE_NAME, (module_info **)&blkman }, { BLKMAN_FOR_DRIVER_MODULE_NAME, (module_info **)&blkman },
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -251,10 +284,13 @@ blkdev_interface scsi_dsk_module = {
std_ops std_ops
}, },
das_supports_device,
das_device_added,
das_init_device, das_init_device,
(status_t (*) (void *))das_uninit_device, (status_t (*) (void *))das_uninit_device,
das_device_added, NULL, // remove device
NULL NULL, // cleanup device
das_get_paths,
}, },
(status_t (*)(blkdev_device_cookie, blkdev_handle_cookie *)) &das_open, (status_t (*)(blkdev_device_cookie, blkdev_handle_cookie *)) &das_open,
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Part of Open SCSI Disk Driver Part of Open SCSI Disk Driver
@@ -17,6 +17,6 @@
#include <device_manager.h> #include <device_manager.h>
#define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/"SCSI_DEVICE_TYPE_NAME #define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/device_v1"
#endif #endif /* _SCSI_DSK_H */
+13 -24
View File
@@ -340,30 +340,16 @@ blkman_ioctl(blkman_handle_info *handle, uint32 op, void *buf, size_t len)
static status_t static status_t
blkman_probe(device_node_handle parent) blkman_register_device(device_node_handle parent)
{ {
char *str;
TRACE(("blkman_probe()\n")); TRACE(("blkman_probe()\n"));
// make sure we can handle this parent device
if (pnp->get_attr_string(parent, "type", &str, false) != B_OK)
return B_ERROR;
if (strcmp(str, BLKDEV_TYPE_NAME) != 0) {
free(str);
return B_ERROR;
}
free(str);
// ready to register at devfs // ready to register at devfs
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
// we always want devfs on top of us // we always want devfs on top of us
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "blkman" }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "blkman" }},
{ NULL } { NULL }
}; };
@@ -505,7 +491,7 @@ blkman_init_device(device_node_handle node, void *user_cookie, void **cookie)
device->params = params; device->params = params;
device->is_bios_drive = is_bios_drive != 0; device->is_bios_drive = is_bios_drive != 0;
res = pnp->load_driver(pnp->get_parent(node), device, res = pnp->init_driver(pnp->get_parent(node), device,
(driver_module_info **)&device->interface, (void **)&device->cookie); (driver_module_info **)&device->interface, (void **)&device->cookie);
if (res != B_OK) if (res != B_OK)
goto err4; goto err4;
@@ -525,7 +511,7 @@ err2:
free(device); free(device);
err1: err1:
free(name); free(name);
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(pnp->get_parent(node));
return res; return res;
} }
@@ -533,7 +519,7 @@ err1:
static status_t static status_t
blkman_uninit_device(blkman_device_info *device) blkman_uninit_device(blkman_device_info *device)
{ {
pnp->unload_driver(pnp->get_parent(device->node)); pnp->uninit_driver(pnp->get_parent(device->node));
locked_pool->destroy(device->phys_vecs_pool); locked_pool->destroy(device->phys_vecs_pool);
benaphore_destroy(&device->lock); benaphore_destroy(&device->lock);
@@ -614,7 +600,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool }, { LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
{} {}
}; };
@@ -628,11 +614,14 @@ pnp_devfs_driver_info blkman_module = {
std_ops std_ops
}, },
NULL, // supports device
blkman_register_device,
blkman_init_device, blkman_init_device,
(status_t (*)( void * )) blkman_uninit_device, (status_t (*)( void * )) blkman_uninit_device,
blkman_probe, blkman_remove,
blkman_remove NULL, // cleanup
NULL, // get paths
}, },
(status_t (*)(void *, uint32, void **))blkman_open, (status_t (*)(void *, uint32, void **))blkman_open,
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Fast logging facilities. Fast logging facilities.
@@ -568,7 +568,7 @@ fast_log_std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
+5 -4
View File
@@ -81,9 +81,8 @@ fast_log_create_devfs_entry(void)
{ {
status_t res; status_t res;
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: FAST_LOG_DEVFS_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: FAST_LOG_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "fast_log" }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "fast_log" }},
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: FAST_LOG_DEVFS_NAME }}, { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: FAST_LOG_DEVFS_NAME }},
@@ -136,12 +135,14 @@ pnp_devfs_driver_info fast_log_devfs_module = {
fast_log_devfs_std_ops fast_log_devfs_std_ops
}, },
NULL,
NULL,
fast_log_devfs_init_device, fast_log_devfs_init_device,
fast_log_devfs_uninit_device, fast_log_devfs_uninit_device,
NULL, NULL,
NULL, NULL,
NULL,
}, },
fast_log_devfs_open, fast_log_devfs_open,
@@ -301,17 +301,18 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel)
if (status.active) { if (status.active) {
SHOW_ERROR0( 2, "DMA transfer aborted" ); SHOW_ERROR0( 2, "DMA transfer aborted" );
return B_ERROR; return B_ERROR;
} else {
SHOW_ERROR0( 2, "DMA transfer: buffer underrun" );
return B_DEV_DATA_UNDERRUN;
} }
} else {
if (status.active) { SHOW_ERROR0( 2, "DMA transfer: buffer underrun" );
SHOW_ERROR0( 2, "DMA transfer: buffer too large" ); return B_DEV_DATA_UNDERRUN;
return B_DEV_DATA_OVERRUN;
} else
return B_OK;
} }
if (status.active) {
SHOW_ERROR0( 2, "DMA transfer: buffer too large" );
return B_DEV_DATA_OVERRUN;
}
return B_OK;
} }
@@ -336,7 +337,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
|| pnp->get_attr_uint8(node, IDE_ADAPTER_IS_PRIMARY, &is_primary, false) != B_OK) || pnp->get_attr_uint8(node, IDE_ADAPTER_IS_PRIMARY, &is_primary, false) != B_OK)
return B_ERROR; return B_ERROR;
if (pnp->load_driver(pnp->get_parent(node), NULL, NULL, (void **)&controller) != B_OK) if (pnp->init_driver(pnp->get_parent(node), NULL, NULL, (void **)&controller) != B_OK)
return B_ERROR; return B_ERROR;
channel = (ide_adapter_channel_info *)malloc(total_data_size); channel = (ide_adapter_channel_info *)malloc(total_data_size);
@@ -389,7 +390,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
err3: err3:
delete_area(channel->prd_area); delete_area(channel->prd_area);
err2: err2:
pnp->unload_driver(pnp->get_parent(node)); pnp->uninit_driver(pnp->get_parent(node));
err: err:
free(channel); free(channel);
@@ -410,7 +411,7 @@ ide_adapter_uninit_channel(ide_adapter_channel_info *channel)
remove_io_interrupt_handler(channel->intnum, channel->inthand, channel); remove_io_interrupt_handler(channel->intnum, channel->inthand, channel);
pnp->unload_driver( pnp->get_parent(channel->node)); pnp->uninit_driver( pnp->get_parent(channel->node));
delete_area(channel->prd_area); delete_area(channel->prd_area);
free(channel); free(channel);
@@ -441,14 +442,10 @@ ide_adapter_publish_channel(device_node_handle controller_node,
{ {
device_attr attrs[] = { device_attr attrs[] = {
// info about ourself and our consumer // info about ourself and our consumer
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: channel_module_name }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: channel_module_name }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }}, { B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "IDE PCI" }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }}, { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "IDE PCI" }}, { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
// disable automatic rescan as we register channels manually
{ PNP_DRIVER_NEVER_RESCAN, B_UINT8_TYPE, { ui8 : 1 }},
// private data to identify channel // private data to identify channel
{ IDE_ADAPTER_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }}, { IDE_ADAPTER_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
@@ -459,7 +456,7 @@ ide_adapter_publish_channel(device_node_handle controller_node,
{ NULL } { NULL }
}; };
SHOW_FLOW0( 2, "" ); SHOW_FLOW0(2, "");
return pnp->register_device(controller_node, attrs, resources, node); return pnp->register_device(controller_node, attrs, resources, node);
} }
@@ -557,7 +554,7 @@ ide_adapter_init_controller(device_node_handle node, void *user_cookie,
if (pnp->get_attr_uint16(node, IDE_ADAPTER_BUS_MASTER_BASE, &bus_master_base, false) != B_OK) if (pnp->get_attr_uint16(node, IDE_ADAPTER_BUS_MASTER_BASE, &bus_master_base, false) != B_OK)
return B_ERROR; return B_ERROR;
if (pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&pci, (void **)&device) != B_OK) if (pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
return B_ERROR; return B_ERROR;
controller = (ide_adapter_controller_info *)malloc(total_data_size); controller = (ide_adapter_controller_info *)malloc(total_data_size);
@@ -579,7 +576,7 @@ ide_adapter_init_controller(device_node_handle node, void *user_cookie,
static status_t static status_t
ide_adapter_uninit_controller(ide_adapter_controller_info *controller) ide_adapter_uninit_controller(ide_adapter_controller_info *controller)
{ {
pnp->unload_driver(pnp->get_parent(controller->node)); pnp->uninit_driver(pnp->get_parent(controller->node));
free(controller); free(controller);
@@ -609,10 +606,7 @@ ide_adapter_publish_controller(device_node_handle parent, uint16 bus_master_base
{ {
device_attr attrs[] = { device_attr attrs[] = {
// info about ourself and our consumer // info about ourself and our consumer
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: controller_driver }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: controller_driver }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: controller_driver_type }},
// don't scan if loaded as we own I/O resources
{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
// properties of this controller for ide bus manager // properties of this controller for ide bus manager
// there are always max. 2 devices // there are always max. 2 devices
@@ -699,7 +693,7 @@ ide_adapter_probe_controller(device_node_handle parent, const char *controller_d
SHOW_FLOW0( 3, "" ); SHOW_FLOW0( 3, "" );
if (pnp->load_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK) if (pnp->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
return B_ERROR; return B_ERROR;
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4 ); command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4 );
@@ -726,12 +720,12 @@ ide_adapter_probe_controller(device_node_handle parent, const char *controller_d
can_dma, command_block_base[0], control_block_base[0], bus_master_base, can_dma, command_block_base[0], control_block_base[0], bus_master_base,
intnum, false, "Secondary Channel", &channels[1], supports_compatibility_mode); intnum, false, "Secondary Channel", &channels[1], supports_compatibility_mode);
pnp->unload_driver(parent); pnp->uninit_driver(parent);
return B_OK; return B_OK;
err: err:
pnp->unload_driver(parent); pnp->uninit_driver(parent);
return res; return res;
} }
@@ -752,7 +746,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide }, { IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -777,7 +771,6 @@ static ide_adapter_interface adapter_interface = {
ide_adapter_start_dma, ide_adapter_start_dma,
ide_adapter_finish_dma, ide_adapter_finish_dma,
ide_adapter_inthand, ide_adapter_inthand,
ide_adapter_init_channel, ide_adapter_init_channel,
@@ -797,11 +790,7 @@ static ide_adapter_interface adapter_interface = {
ide_adapter_probe_controller ide_adapter_probe_controller
}; };
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = { module_info *modules[] = {
&adapter_interface.info, &adapter_interface.info,
NULL NULL
}; };
#endif
@@ -1,7 +1,7 @@
/* /*
** Copyright 2002/03, Thomas Kurschel. All rights reserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License. * Distributed under the terms of the MIT License.
*/ */
/* /*
Part of Open SCSI Peripheral Driver Part of Open SCSI Peripheral Driver
@@ -128,7 +128,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{} {}
}; };
@@ -164,11 +164,7 @@ scsi_periph_interface scsi_periph_module = {
periph_get_icon periph_get_icon
}; };
#if !_BUILDING_kernel && !BOOT
_EXPORT
scsi_periph_interface *modules[] = { scsi_periph_interface *modules[] = {
&scsi_periph_module, &scsi_periph_module,
NULL NULL
}; };
#endif
+53 -12
View File
@@ -168,19 +168,19 @@ pnp_get_attr_string_nolock(device_node_handle node, const char *name,
status_t status_t
pnp_get_attr_raw(device_node_handle node, const char *name, pnp_get_attr_raw(device_node_handle node, const char *name,
void **data, size_t *len, bool recursive) void **data, size_t *length, bool recursive)
{ {
const void *orig_data; const void *orig_data;
status_t status; status_t status;
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
status = pnp_get_attr_raw_nolock( node, name, &orig_data, len, recursive ); status = pnp_get_attr_raw_nolock( node, name, &orig_data, length, recursive );
if (status == B_OK) { if (status == B_OK) {
void *tmp_data = malloc(*len); void *tmp_data = malloc(*length);
if (tmp_data != NULL) { if (tmp_data != NULL) {
memcpy(tmp_data, orig_data, *len); memcpy(tmp_data, orig_data, *length);
*data = tmp_data; *data = tmp_data;
} else } else
status = B_NO_MEMORY; status = B_NO_MEMORY;
@@ -194,18 +194,61 @@ pnp_get_attr_raw(device_node_handle node, const char *name,
status_t status_t
pnp_get_attr_raw_nolock(device_node_handle node, const char *name, pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
const void **data, size_t *len, bool recursive) const void **data, size_t *length, bool recursive)
{ {
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_RAW_TYPE); device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_RAW_TYPE);
if (attr == NULL) if (attr == NULL)
return B_NAME_NOT_FOUND; return B_NAME_NOT_FOUND;
*data = attr->attr.value.raw.data; *data = attr->attr.value.raw.data;
*len = attr->attr.value.raw.len; *length = attr->attr.value.raw.length;
return B_OK; return B_OK;
} }
/** Compare two attributes for */
int
pnp_compare_attrs(const device_attr *attrA, const device_attr *attrB)
{
if (attrA->type != attrB->type)
return -1;
switch (attrA->type) {
case B_UINT8_TYPE:
return (int)attrA->value.ui8 - (int)attrB->value.ui8;
case B_UINT16_TYPE:
return (int)attrA->value.ui16 - (int)attrB->value.ui16;
case B_UINT32_TYPE:
if (attrA->value.ui32 > attrB->value.ui32)
return 1;
if (attrA->value.ui32 < attrB->value.ui32)
return -1;
return 0;
case B_UINT64_TYPE:
if (attrA->value.ui64 > attrB->value.ui64)
return 1;
if (attrA->value.ui64 < attrB->value.ui64)
return -1;
return 0;
case B_STRING_TYPE:
return strcmp(attrA->value.string, attrB->value.string);
case B_RAW_TYPE:
if (attrA->value.raw.length != attrB->value.raw.length)
return -1;
return memcmp(attrA->value.raw.data, attrB->value.raw.data, attrA->value.raw.length);
}
return -1;
}
// free node attribute // free node attribute
void void
@@ -260,15 +303,15 @@ pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out)
break; break;
case B_RAW_TYPE: case B_RAW_TYPE:
dest->attr.value.raw.data = malloc(src->value.raw.len); dest->attr.value.raw.data = malloc(src->value.raw.length);
if (dest->attr.value.raw.data == NULL) { if (dest->attr.value.raw.data == NULL) {
res = B_NO_MEMORY; res = B_NO_MEMORY;
goto err; goto err;
} }
dest->attr.value.raw.len = src->value.raw.len; dest->attr.value.raw.length = src->value.raw.length;
memcpy(dest->attr.value.raw.data, src->value.raw.data, memcpy(dest->attr.value.raw.data, src->value.raw.data,
src->value.raw.len); src->value.raw.length);
break; break;
default: default:
@@ -448,10 +491,8 @@ static bool
is_fixed_attribute(const char *name) is_fixed_attribute(const char *name)
{ {
static const char *forbidden_list[] = { static const char *forbidden_list[] = {
PNP_DRIVER_DRIVER, // never change driver B_DRIVER_MODULE, // never change driver
PNP_DRIVER_TYPE, // never change type
PNP_BUS_IS_BUS, // never switch between bus/not bus mode PNP_BUS_IS_BUS, // never switch between bus/not bus mode
PNP_DRIVER_ALWAYS_LOADED // don't confuse us by changing auto-load
}; };
uint32 i; uint32 i;
@@ -26,7 +26,7 @@
#endif #endif
device_node_info *gNodeList; device_node_info *gRootNode;
bool disable_useraddons; bool disable_useraddons;
@@ -35,17 +35,13 @@ sem_id pnp_resource_wait_sem;
io_resource_info *io_mem_list, *io_port_list, *isa_dma_list; io_resource_info *io_mem_list, *io_port_list, *isa_dma_list;
#if 0
void static int
check_settings() dump_device_nodes(int argc, char **argv)
{ {
void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); dm_dump_node(gRootNode, 0);
return 0;
disable_useraddons = get_driver_boolean_parameter(settings, "disableuseraddons", 0, 1);
unload_driver_settings(settings);
} }
#endif
static status_t static status_t
@@ -70,7 +66,7 @@ std_ops(int32 op, ...)
device_manager_info gDeviceManagerModule = { device_manager_info gDeviceManagerModule = {
{ {
DEVICE_MANAGER_MODULE_NAME, B_DEVICE_MANAGER_MODULE_NAME,
0, 0,
std_ops std_ops
}, },
@@ -78,20 +74,21 @@ device_manager_info gDeviceManagerModule = {
pnp_load_driver, pnp_load_driver,
pnp_unload_driver, pnp_unload_driver,
pnp_rescan, dm_rescan,
pnp_register_device, dm_register_node,
pnp_unregister_device, dm_unregister_node,
pnp_acquire_io_resources, dm_get_next_child_node,
pnp_release_io_resources, dm_get_parent,
dm_put_node,
pnp_find_device, dm_acquire_io_resources,
dm_release_io_resources,
pnp_create_id, dm_create_id,
pnp_free_id, dm_free_id,
pnp_get_parent,
pnp_get_attr_uint8, pnp_get_attr_uint8,
pnp_get_attr_uint16, pnp_get_attr_uint16,
pnp_get_attr_uint32, pnp_get_attr_uint32,
@@ -102,7 +99,8 @@ device_manager_info gDeviceManagerModule = {
pnp_get_next_attr, pnp_get_next_attr,
pnp_release_attr, pnp_release_attr,
pnp_retrieve_attr, pnp_retrieve_attr,
pnp_write_attr pnp_write_attr,
NULL // remove_attr
}; };
@@ -119,13 +117,13 @@ device_manager_init(struct kernel_args *args)
TRACE(("device manager init\n")); TRACE(("device manager init\n"));
status = id_generator_init(); status = dm_init_id_generator();
if (status < B_OK) { if (status < B_OK) {
panic("could not initialize ID generator\n"); panic("could not initialize ID generator\n");
return status; return status;
} }
status = nodes_init(); status = dm_init_nodes();
if (status < B_OK) { if (status < B_OK) {
panic("could not initialize device nodes\n"); panic("could not initialize device nodes\n");
return status; return status;
@@ -141,14 +139,14 @@ device_manager_init(struct kernel_args *args)
io_mem_list = io_port_list = isa_dma_list = NULL; io_mem_list = io_port_list = isa_dma_list = NULL;
pnp_fs_emulation_nesting = 0; pnp_fs_emulation_nesting = 0;
pnp_root_init_root(); dm_init_root_node();
{ {
// dump root node // dump root node
device_node_info *node = gNodeList; device_node_info *node = gRootNode;
while (node && node->parent != NULL) while (node && node->parent != NULL)
node = node->parent; node = node->parent;
dump_device_node_info(node, 0); dm_dump_node(node, 0);
} }
// build initial device tree; register all root bus_managers // build initial device tree; register all root bus_managers
@@ -164,6 +162,7 @@ device_manager_init(struct kernel_args *args)
} }
#endif #endif
add_debugger_command("dm_tree", &dump_device_nodes, "dump device node tree");
return B_OK; return B_OK;
} }
@@ -30,17 +30,15 @@
#define SYSTEM_MODULES_DIR "/boot/beos/add-ons/kernel/" #define SYSTEM_MODULES_DIR "/boot/beos/add-ons/kernel/"
#define COMMON_MODULES_DIR "/boot/home/config/add-ons/kernel/" #define COMMON_MODULES_DIR "/boot/home/config/add-ons/kernel/"
#define PNP_BOOT_LINKS "pnp_bootlinks"
// info about ID generator // info about ID generator
typedef struct id_generator { typedef struct id_generator {
struct list_link link; struct list_link link;
struct id_generator *prev, *next; struct id_generator *prev, *next;
int ref_count; int32 ref_count;
char *name; char *name;
uint32 num_ids; uint32 num_ids;
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8]; uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
} id_generator; } id_generator;
@@ -60,11 +58,18 @@ typedef struct io_resource_info {
} io_resource_info; } io_resource_info;
// a structure to put nodes into lists
struct node_entry {
struct list_link link;
device_node_info *node;
};
// global lock // global lock
// whenever you do something in terms of nodes, grab it // whenever you do something in terms of nodes, grab it
extern benaphore gNodeLock; extern benaphore gNodeLock;
// list of nodes (includes removed devices!) // root node
extern device_node_info *gNodeList; extern device_node_info *gRootNode;
// true, if user addons are disabled via safemode // true, if user addons are disabled via safemode
extern bool disable_useraddons; extern bool disable_useraddons;
@@ -120,6 +125,8 @@ status_t pnp_get_attr_raw(device_node_handle node, const char *name,
status_t pnp_get_attr_raw_nolock(device_node_handle node, const char *name, status_t pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
const void **data, size_t *len, bool recursive); const void **data, size_t *len, bool recursive);
void pnp_free_node_attr(device_attr_info *attr); void pnp_free_node_attr(device_attr_info *attr);
status_t pnp_get_next_node_with_attrs(device_node_info **_node, const device_attr *attrs);
int pnp_compare_attrs(const device_attr *attrA, const device_attr *attrB);
status_t pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out); status_t pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out);
status_t pnp_get_next_attr(device_node_handle node, device_attr_handle *attr); status_t pnp_get_next_attr(device_node_handle node, device_attr_handle *attr);
status_t pnp_release_attr(device_node_handle node, device_attr_handle attr); status_t pnp_release_attr(device_node_handle node, device_attr_handle attr);
@@ -129,62 +136,49 @@ void pnp_remove_attr_int(device_node_handle node, device_attr_info *attr);
status_t pnp_remove_attr(device_node_handle node, const char *name); status_t pnp_remove_attr(device_node_handle node, const char *name);
// boot_hack.c
#if 0
void pnp_load_boot_links( void );
void pnp_unload_boot_links( void );
char *pnp_boot_safe_realpath(
const char *file_name, char *resolved_path );
int pnp_boot_safe_lstat( const char *file_name, struct stat *info );
DIR *pnp_boot_safe_opendir( const char *dirname );
int pnp_boot_safe_closedir( DIR *dirp );
struct dirent *pnp_boot_safe_readdir( DIR *dirp );
#endif
// driver_loader.c // driver_loader.c
status_t pnp_load_driver(device_node_handle node, void *user_cookie, status_t pnp_load_driver(device_node_handle node, void *user_cookie,
driver_module_info **interface, void **cookie); driver_module_info **interface, void **cookie);
status_t pnp_unload_driver(device_node_handle node); status_t pnp_unload_driver(device_node_handle node);
void pnp_unblock_load(device_node_info *node); void pnp_unblock_load(device_node_info *node);
void pnp_load_driver_automatically(device_node_info *node, bool after_rescan);
void pnp_unload_driver_automatically(device_node_info *node, bool before_rescan);
// id_generator.c // id_generator.c
int32 pnp_create_id(const char *name); int32 dm_create_id(const char *name);
status_t pnp_free_id(const char *name, uint32 id); status_t dm_free_id(const char *name, uint32 id);
extern status_t id_generator_init(void); extern status_t dm_init_id_generator(void);
// io_resources.c // io_resources.c
status_t pnp_acquire_io_resources(io_resource *resources, io_resource_handle *handles); status_t dm_acquire_io_resources(io_resource *resources, io_resource_handle *handles);
status_t pnp_release_io_resources(const io_resource_handle *handles); status_t dm_release_io_resources(const io_resource_handle *handles);
void pnp_assign_io_resources(device_node_info *node, const io_resource_handle *handles); void dm_assign_io_resources(device_node_info *node, const io_resource_handle *handles);
void pnp_release_node_resources(device_node_info *node); void dm_release_node_resources(device_node_info *node);
// nodes.c // nodes.c
status_t pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources, status_t dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
device_node_info **new_node); device_node_info **new_node);
void pnp_create_node_links(device_node_info *node, device_node_info *parent); void dm_add_child_node(device_node_info *node, device_node_info *parent);
void pnp_add_node_ref(device_node_info *node); void dm_get_node_nolock(device_node_info *node);
void pnp_remove_node_ref(device_node_info *node); void dm_get_node(device_node_info *node);
void pnp_remove_node_ref_nolock(device_node_info *node); void dm_put_node_nolock(device_node_info *node);
device_node_handle pnp_find_device(device_node_handle parent, const device_attr *attrs); void dm_dump_node(device_node_info *node, int32 level);
device_node_handle pnp_get_parent(device_node_handle node); status_t dm_init_nodes(void);
void dump_device_node_info(device_node_info *node, int32 level);
extern status_t nodes_init(void); void dm_put_node(device_node_info *node);
status_t dm_get_next_child_node(device_node_info *parent,
device_node_info **_node, const device_attr *attrs);
device_node_info *dm_get_parent(device_node_info *node);
// notifications.c // notifications.c
status_t pnp_notify_probe_by_module(device_node_info *node, status_t dm_notify_unregistration(device_node_info *node);
const char *consumer_name);
void pnp_notify_unregistration(device_node_info *notify_list);
void pnp_start_hook_call(device_node_info *node); void pnp_start_hook_call(device_node_info *node);
void pnp_start_hook_call_nolock(device_node_info *node); void pnp_start_hook_call_nolock(device_node_info *node);
void pnp_finish_hook_call(device_node_info *node); void pnp_finish_hook_call(device_node_info *node);
@@ -199,35 +193,30 @@ status_t pnp_expand_pattern_attr(device_node_info *node, const char *attr_name,
char **expanded); char **expanded);
// probe.c // probe.cpp
status_t pnp_notify_fixed_consumers(device_node_handle node); status_t dm_register_child_device(device_node_info *node, const char *childName);
status_t pnp_notify_dynamic_consumers(device_node_info *node); status_t dm_register_fixed_child_devices(device_node_info *node);
status_t dm_register_dynamic_child_devices(device_node_info *node);
// registration.c // registration.c
status_t pnp_register_device(device_node_handle parent, const device_attr *attrs, status_t dm_register_node(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *resources, device_node_handle *node); const io_resource_handle *resources, device_node_handle *_newNode);
status_t pnp_unregister_device(device_node_handle node); status_t dm_unregister_node(device_node_handle node);
void pnp_unregister_node_rec(device_node_info *node, device_node_info **dependency_list);
void pnp_unref_unregistered_nodes(device_node_info *node_list); void pnp_unref_unregistered_nodes(device_node_info *node_list);
void pnp_defer_probing_of_children_nolock(device_node_info *node);
void pnp_defer_probing_of_children(device_node_info *node);
void pnp_probe_waiting_children_nolock(device_node_info *node);
void pnp_probe_waiting_children(device_node_info *node);
// root_node.c // root_node.c
extern void pnp_root_init_root(void); void dm_init_root_node(void);
extern void pnp_root_destroy_root(void);
extern void pnp_root_rescan_root(void);
// scan.c // scan.c
status_t pnp_rescan(device_node_handle node, uint32 depth); status_t dm_rescan(device_node_handle node);
status_t pnp_rescan_int(device_node_info *node, uint32 depth, status_t dm_register_child_devices(device_node_info *node);
bool ignore_fixed_consumers);
status_t pnp_initial_scan(device_node_info *node);
#ifdef __cplusplus #ifdef __cplusplus
} }
+43 -155
View File
@@ -69,103 +69,6 @@ pnp_wait_load_block(device_node_info *node)
} }
/** load driver automatically after registration/rescan of node. */
void
pnp_load_driver_automatically(device_node_info *node, bool after_rescan)
{
uint8 always_loaded;
status_t res;
driver_module_info *interface;
void *cookie;
benaphore_lock(&gNodeLock);
// ignore dead nodes
if (!node->registered)
goto err;
if (node->automatically_loaded)
goto err;
if (pnp_get_attr_uint8_nolock(node, PNP_DRIVER_ALWAYS_LOADED,
&always_loaded, false ) != B_OK)
goto err;
if (always_loaded < 1 || always_loaded > 2)
goto err;
// this test is probably useless as the driver would be kept loaded
// during rescan anyway
if (always_loaded == 2 && after_rescan)
goto err;
// alright - time to get the driver loaded
benaphore_unlock(&gNodeLock);
res = pnp_load_driver(node, NULL, &interface, &cookie);
benaphore_lock(&gNodeLock);
// if driver cannot be loaded, we don't really care
if (res == B_OK )
node->automatically_loaded = true;
else
dprintf("driver could not be automatically loaded\n");
err:
benaphore_unlock(&gNodeLock);
return;
}
/** unload driver that got loaded automatically. */
void
pnp_unload_driver_automatically(device_node_info *node, bool before_rescan)
{
uint8 always_loaded;
status_t res;
benaphore_lock(&gNodeLock);
if (!node->automatically_loaded)
goto err;
if (pnp_get_attr_uint8_nolock(node, PNP_DRIVER_ALWAYS_LOADED,
&always_loaded, false) != B_OK)
goto err;
// this test is probably useless as the driver wouldn't be
// loaded anyway
if (always_loaded < 1 || always_loaded > 2)
goto err;
if (always_loaded == 2 && before_rescan)
goto err;
// time to unload the driver
benaphore_unlock(&gNodeLock);
res = pnp_unload_driver(node);
benaphore_lock(&gNodeLock);
// don't reset flag if unloading failed;
// if this happens during unregistration, this won't help;
// but if this happens during rescan, the driver only stays
// loaded during rescan, which can be handled
if (res == B_OK)
node->automatically_loaded = false;
else
dprintf("driver could not be unloaded during scan\n");
err:
benaphore_unlock(&gNodeLock);
return;
}
/** load driver for real /** load driver for real
* (loader_lock must be hold) * (loader_lock must be hold)
*/ */
@@ -173,49 +76,48 @@ err:
static status_t static status_t
load_driver_int(device_node_info *node, void *user_cookie) load_driver_int(device_node_info *node, void *user_cookie)
{ {
char *module_name;
driver_module_info *driver; driver_module_info *driver;
char *moduleName;
void *cookie; void *cookie;
status_t res; status_t status;
TRACE(("load_driver_int()\n")); TRACE(("load_driver_int()\n"));
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false); status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
if (res != B_OK) if (status != B_OK)
return res; return status;
TRACE(("%s\n", module_name)); TRACE(("%s\n", moduleName));
res = get_module(module_name, (module_info **)&driver); status = get_module(moduleName, (module_info **)&driver);
if (res < B_OK) { if (status < B_OK) {
dprintf("Cannot load module %s\n", module_name); dprintf("Cannot load module %s\n", moduleName);
goto err; goto err1;
} }
if (driver->init_device == NULL) { if (driver->init_driver == NULL) {
dprintf("Driver %s has no init_device hook\n", module_name); dprintf("Driver %s has no init_driver hook\n", moduleName);
res = B_ERROR; status = B_ERROR;
goto err2; goto err2;
} }
res = driver->init_device(node, user_cookie, &cookie); status = driver->init_driver(node, user_cookie, &cookie);
if (res < B_OK) { if (status < B_OK) {
dprintf("init device failed (node %p, %s): %s\n", node, module_name, strerror(res)); dprintf("init driver failed (node %p, %s): %s\n", node, moduleName, strerror(status));
goto err2; goto err2;
} }
node->driver = driver; node->driver = driver;
node->cookie = cookie; node->cookie = cookie;
free(module_name); free(moduleName);
return B_OK; return B_OK;
err2: err2:
put_module(module_name); put_module(moduleName);
err1:
err: free(moduleName);
free(module_name); return status;
return res;
} }
@@ -257,12 +159,6 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
// make sure noone else load/unloads/notifies the driver // make sure noone else load/unloads/notifies the driver
pnp_start_hook_call_nolock(node); pnp_start_hook_call_nolock(node);
// during load, driver may register children;
// probing them for consumers may be impossible as they
// may try to load driver -> deadlock
// so we block probing for consumers of children
pnp_defer_probing_of_children_nolock(node);
if (!node->registered) { if (!node->registered) {
// device got lost meanwhile // device got lost meanwhile
TRACE(("Device got lost during wait\n")); TRACE(("Device got lost during wait\n"));
@@ -296,16 +192,11 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
if (res == B_OK) { if (res == B_OK) {
// everything went fine - increase load counter // everything went fine - increase load counter
++node->load_count; ++node->load_count;
// now we can safely probe for consumers of children as the
// driver is fully loaded
pnp_probe_waiting_children_nolock(node);
} else { } else {
// loading failed or device got removed - restore reference count; // loading failed or device got removed - restore reference count;
// but first (i.e. as long as ref_count is increased) get // but first (i.e. as long as ref_count is increased) get
// rid of waiting children // rid of waiting children
pnp_probe_waiting_children_nolock(node); dm_put_node_nolock(node);
pnp_remove_node_ref_nolock(node);
} }
} else { } else {
// driver is already loaded, so increase load_count // driver is already loaded, so increase load_count
@@ -323,7 +214,7 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
*cookie = node->cookie; *cookie = node->cookie;
TRACE(("load_driver: Success \"%s\"\n", TRACE(("load_driver: Success \"%s\"\n",
((struct module_info *)(*interface))->name)); ((struct module_info *)node->driver)->name));
} else { } else {
TRACE(("load_driver: Failure (%s)\n", strerror(res))); TRACE(("load_driver: Failure (%s)\n", strerror(res)));
} }
@@ -338,26 +229,26 @@ static status_t
unload_driver_int(device_node_info *node) unload_driver_int(device_node_info *node)
{ {
driver_module_info *driver = node->driver; driver_module_info *driver = node->driver;
char *module_name; char *moduleName;
status_t res; status_t status;
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false); status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
if (res != B_OK) if (status != B_OK)
return res; return status;
TRACE(("unload_driver_int: %s\n", module_name)); TRACE(("unload_driver_int: %s\n", moduleName));
if (driver->uninit_device == NULL) { if (driver->uninit_driver == NULL) {
// it has no uninit - we can't unload it, so it stays in memory forever // it has no uninit - we can't unload it, so it stays in memory forever
TRACE(("Driver %s has no uninit_device hook\n", module_name)); TRACE(("Driver %s has no uninit_device hook\n", moduleName));
res = B_ERROR; status = B_ERROR;
goto err; goto out;
} }
res = driver->uninit_device(node->cookie); status = driver->uninit_driver(node->cookie);
if (res != B_OK) { if (status != B_OK) {
TRACE(("Failed to uninit driver %s (%s)\n", module_name, strerror(res))); TRACE(("Failed to uninit driver %s (%s)\n", moduleName, strerror(status)));
goto err; goto out;
} }
// if it was unregistered a while ago but couldn't get cleaned up // if it was unregistered a while ago but couldn't get cleaned up
@@ -367,14 +258,11 @@ unload_driver_int(device_node_info *node)
driver->device_cleanup(node); driver->device_cleanup(node);
} }
put_module(module_name); put_module(moduleName);
free(module_name); out:
return B_OK; free(moduleName);
return status;
err:
free(module_name);
return res;
} }
@@ -428,7 +316,7 @@ pnp_unload_driver(device_node_handle node)
// everything is fine, so decrease load_count ... // everything is fine, so decrease load_count ...
--node->load_count; --node->load_count;
// ... and reference count // ... and reference count
pnp_remove_node_ref_nolock(node); dm_put_node_nolock(node);
} else { } else {
// unloading failed: leave loaded in memory forever // unloading failed: leave loaded in memory forever
// as load_count is not decreased, the driver will never // as load_count is not decreased, the driver will never
@@ -443,7 +331,7 @@ pnp_unload_driver(device_node_handle node)
// no concurrent load/unload and load_count won't reach zero // no concurrent load/unload and load_count won't reach zero
--node->load_count; --node->load_count;
// each load increased reference count by one - time to undo that // each load increased reference count by one - time to undo that
pnp_remove_node_ref_nolock(node); dm_put_node_nolock(node);
res = B_OK; res = B_OK;
} }
@@ -159,7 +159,7 @@ release_generator(id_generator *generator)
status_t status_t
id_generator_init(void) dm_init_id_generator(void)
{ {
list_init(&sGenerators); list_init(&sGenerators);
return benaphore_init(&sGeneratorLock, "id generator"); return benaphore_init(&sGeneratorLock, "id generator");
@@ -167,13 +167,13 @@ id_generator_init(void)
// #pragma mark - // #pragma mark -
// Public API // Public module API
/** Create automatic ID */ /** Create automatic ID */
int32 int32
pnp_create_id(const char *name) dm_create_id(const char *name)
{ {
id_generator *generator; id_generator *generator;
int32 id; int32 id;
@@ -203,7 +203,7 @@ pnp_create_id(const char *name)
/** Free automatically generated ID */ /** Free automatically generated ID */
status_t status_t
pnp_free_id(const char *name, uint32 id) dm_free_id(const char *name, uint32 id)
{ {
id_generator *generator; id_generator *generator;
+99 -87
View File
@@ -67,17 +67,17 @@ validate_io_resource(io_resource *src)
switch (src->type) { switch (src->type) {
case IO_MEM: case IO_MEM:
if (src->base + src->len < src->base) if (src->base + src->length < src->base)
return B_BAD_VALUE; return B_BAD_VALUE;
break; break;
case IO_PORT: case IO_PORT:
if ((uint16)src->base != src->base if ((uint16)src->base != src->base
|| (uint16)src->len != src->len || (uint16)src->length != src->length
|| (uint16)(src->base + src->len) < src->base) || (uint16)(src->base + src->length) < src->base)
return B_BAD_VALUE; return B_BAD_VALUE;
break; break;
case ISA_DMA_CHANNEL: case ISA_DMA_CHANNEL:
if (src->base > 8 || src->len != 1) if (src->base > 8 || src->length != 1)
return B_BAD_VALUE; return B_BAD_VALUE;
break; break;
@@ -107,7 +107,7 @@ alloc_io_resource_info(io_resource *src, io_resource_info **dest_out)
dest->resource.type = src->type; dest->resource.type = src->type;
dest->resource.base = src->base; dest->resource.base = src->base;
dest->resource.len = src->len; dest->resource.length = src->length;
*dest_out = dest; *dest_out = dest;
return B_OK; return B_OK;
@@ -123,15 +123,15 @@ acquire_range(io_resource_info **list, io_resource_info *resource)
{ {
io_resource_info *cur; io_resource_info *cur;
uint32 base = resource->resource.base; uint32 base = resource->resource.base;
uint32 len = resource->resource.len; uint32 length = resource->resource.length;
status_t res = B_OK; status_t res = B_OK;
TRACE(("acquire_range(base %lx, len %lx)\n", base, len)); TRACE(("acquire_range(base %lx, length %lx)\n", base, length));
for (cur = *list; cur != NULL; cur = cur->next) { for (cur = *list; cur != NULL; cur = cur->next) {
// we need the "base + len - 1" trick to avoid wrap around at 4 GB // we need the "base + length - 1" trick to avoid wrap around at 4 GB
if (cur->resource.base >= base if (cur->resource.base >= base
&& cur->resource.base + len - 1 <= base + len - 1) { && cur->resource.base + length - 1 <= base + length - 1) {
device_node_info *owner = cur->owner; device_node_info *owner = cur->owner;
TRACE(("collision\n")); TRACE(("collision\n"));
@@ -180,18 +180,19 @@ acquire_range(io_resource_info **list, io_resource_info *resource)
static void static void
free_io_resource_info(io_resource_info *resource) free_io_resource_info(io_resource_info *resource)
{ {
TRACE(("free_io_resource_info")); TRACE(("free_io_resource_info()\n"));
free(resource); free(resource);
} }
// acquire I/O resource /** Acquire I/O resource.
// a I/O resource info structure is allocated and added to * An I/O resource info structure is allocated and added to
// appropriate resource list (i.e. mem/port/channel) plus * appropriate resource list (i.e. mem/port/channel) plus
// all colliding resources (including ours) are marked blocked; * all colliding resources (including ours) are marked blocked;
// returns B_WOULD_BLOCK on collision with temporary allocation; * returns B_WOULD_BLOCK on collision with temporary allocation;
// node_lock must be hold * gNodeLock must be hold.
*/
static status_t static status_t
acquire_io_resource(io_resource *src, io_resource_handle *dest_out) acquire_io_resource(io_resource *src, io_resource_handle *dest_out)
@@ -199,7 +200,8 @@ acquire_io_resource(io_resource *src, io_resource_handle *dest_out)
io_resource_info *dest; io_resource_info *dest;
status_t res; status_t res;
TRACE(("acquire_io_resource(type=%ld, base=%lx, len=%lx)\n", src->type, src->base, src->len)); TRACE(("acquire_io_resource(type = %ld, base = %lx, length = %lx)\n",
src->type, src->base, src->length));
res = validate_io_resource(src); res = validate_io_resource(src);
if (res != B_OK) if (res != B_OK)
@@ -273,7 +275,7 @@ release_range(io_resource_info **list, io_resource_info *resource, io_resource_i
{ {
io_resource_info *cur; io_resource_info *cur;
uint32 base = resource->resource.base; uint32 base = resource->resource.base;
uint32 len = resource->resource.len; uint32 length = resource->resource.length;
TRACE(("release_range()\n")); TRACE(("release_range()\n"));
@@ -282,8 +284,8 @@ release_range(io_resource_info **list, io_resource_info *resource, io_resource_i
// ignore ourselves // ignore ourselves
continue; continue;
// we need the "base + len - 1" trick to avoid wrap around at 4 GB // we need the "base + length - 1" trick to avoid wrap around at 4 GB
if (cur->resource.base >= base && cur->resource.base + len - 1 <= base + len - 1) { if (cur->resource.base >= base && cur->resource.base + length - 1 <= base + length - 1) {
device_node_info *owner = cur->owner; device_node_info *owner = cur->owner;
TRACE(("unblock\n")); TRACE(("unblock\n"));
@@ -391,46 +393,6 @@ status_t acquire_io_resources(io_resource *resources, io_resource_handle *handle
} }
// public: acquire I/O resources
status_t
pnp_acquire_io_resources(io_resource *resources, io_resource_handle *handles)
{
status_t res;
TRACE(("pnp_acquire_io_resources()\n"));
benaphore_lock(&gNodeLock);
res = acquire_io_resources(resources, handles);
benaphore_unlock(&gNodeLock);
TRACE(("done (%s)", strerror(res)));
return res;
}
// public: release I/O resources
status_t
pnp_release_io_resources(const io_resource_handle *handles)
{
io_resource_info *const *resource;
if (handles == NULL)
return B_OK;
benaphore_lock(&gNodeLock);
for (resource = handles; *resource != NULL; ++resource)
release_io_resource(*resource);
benaphore_unlock(&gNodeLock);
return B_OK;
}
// unregister devices that collide with one of our I/O resources // unregister devices that collide with one of our I/O resources
static void static void
@@ -461,7 +423,7 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
{ {
io_resource_info *cur; io_resource_info *cur;
uint32 base = resource->resource.base; uint32 base = resource->resource.base;
uint32 len = resource->resource.len; uint32 length = resource->resource.length;
do { do {
for (cur = list; cur != NULL; cur = cur->next) { for (cur = list; cur != NULL; cur = cur->next) {
@@ -469,9 +431,9 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
if (cur == resource) if (cur == resource)
continue; continue;
// we need the "base + len - 1" trick to avoid wrap around at 4 GB // we need the "base + length - 1" trick to avoid wrap around at 4 GB
if (cur->resource.base >= base if (cur->resource.base >= base
&& cur->resource.base + len - 1 <= base + len - 1) { && cur->resource.base + length - 1 <= base + length - 1) {
device_node_handle owner = cur->owner; device_node_handle owner = cur->owner;
if (owner == NULL) if (owner == NULL)
@@ -487,11 +449,11 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
// unregister device node - we own its resources now // unregister device node - we own its resources now
// (its resources are freed by the next remove_node_ref call) // (its resources are freed by the next remove_node_ref call)
pnp_unregister_device(owner); dm_unregister_node(owner);
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
pnp_remove_node_ref_nolock(owner); dm_put_node_nolock(owner);
// restart loop as resource list may have changed meanwhile // restart loop as resource list may have changed meanwhile
break; break;
} }
@@ -500,11 +462,31 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
} }
// transfer temporary I/O resources to device node; /** unblock other temporary allocations so they can retry
// colliding devices are unregistered * gNodeLock must be hold
*/
static void
unblock_temporary_allocation(void)
{
if (pnp_resource_wait_count > 0) {
TRACE(("unblock concurrent temporary allocation\n"));
release_sem_etc(pnp_resource_wait_sem, pnp_resource_wait_count, 0);
pnp_resource_wait_count = 0;
}
}
// #pragma mark -
/** transfer temporary I/O resources to device node;
* colliding devices are unregistered
*/
void void
pnp_assign_io_resources(device_node_info *node, const io_resource_handle *resources) dm_assign_io_resources(device_node_info *node, const io_resource_handle *resources)
{ {
io_resource_handle *resource; io_resource_handle *resource;
@@ -531,27 +513,13 @@ pnp_assign_io_resources(device_node_info *node, const io_resource_handle *resour
} }
// unblock other temporary allocations so they can retry /** release I/O resources of a device node and set list to NULL;
// node_lock must be hold * users previously blocked by our resource alloction are notified;
* gNodeLock must be hold
static void */
unblock_temporary_allocation(void)
{
if (pnp_resource_wait_count > 0) {
TRACE(("unblock concurrent temporary allocation\n"));
release_sem_etc(pnp_resource_wait_sem, pnp_resource_wait_count, 0);
pnp_resource_wait_count = 0;
}
}
// release I/O resources of a device node and set list to NULL;
// users previously blocked by our resource alloction are notified;
// node_lock must be hold
void void
pnp_release_node_resources(device_node_info *node) dm_release_node_resources(device_node_info *node)
{ {
io_resource_handle *resource; io_resource_handle *resource;
@@ -568,3 +536,47 @@ pnp_release_node_resources(device_node_info *node)
*node->io_resources = NULL; *node->io_resources = NULL;
} }
// #pragma mark -
// Part of the module API
/** acquire I/O resources */
status_t
dm_acquire_io_resources(io_resource *resources, io_resource_handle *handles)
{
status_t res;
TRACE(("pnp_acquire_io_resources()\n"));
benaphore_lock(&gNodeLock);
res = acquire_io_resources(resources, handles);
benaphore_unlock(&gNodeLock);
TRACE(("done (%s)", strerror(res)));
return res;
}
/** release I/O resources */
status_t
dm_release_io_resources(const io_resource_handle *handles)
{
io_resource_info *const *resource;
if (handles == NULL)
return B_OK;
benaphore_lock(&gNodeLock);
for (resource = handles; *resource != NULL; ++resource)
release_io_resource(*resource);
benaphore_unlock(&gNodeLock);
return B_OK;
}
+195 -200
View File
@@ -42,24 +42,50 @@
benaphore gNodeLock; benaphore gNodeLock;
// increase ref_count of node static void
put_level(int32 level)
void
pnp_add_node_ref(device_node_info *node)
{ {
TRACE(("add_node_ref(%p)\n", node)); while (level-- > 0)
dprintf(" ");
if (node == NULL)
return;
benaphore_lock(&gNodeLock);
node->ref_count++;
benaphore_unlock(&gNodeLock);
} }
// free attributes of node static void
// if an attribute is still in use, it's deletion is postponed dump_attribute(device_attr_info *attr, int32 level)
{
if (attr == NULL)
return;
put_level(level + 2);
dprintf("\"%s\" : ", attr->attr.name);
switch (attr->attr.type) {
case B_STRING_TYPE:
dprintf("string : \"%s\"", attr->attr.value.string);
break;
case B_UINT8_TYPE:
dprintf("uint8 : %u (%#x)", attr->attr.value.ui8, attr->attr.value.ui8);
break;
case B_UINT16_TYPE:
dprintf("uint16 : %u (%#x)", attr->attr.value.ui16, attr->attr.value.ui16);
break;
case B_UINT32_TYPE:
dprintf("uint32 : %lu (%#lx)", attr->attr.value.ui32, attr->attr.value.ui32);
break;
case B_UINT64_TYPE:
dprintf("uint64 : %Lu (%#Lx)", attr->attr.value.ui64, attr->attr.value.ui64);
break;
default:
dprintf("raw data");
}
dprintf("\n");
dump_attribute(attr->next, level);
}
/** free attributes of node
* if an attribute is still in use, it's deletion is postponed
*/
static void static void
free_node_attrs(device_node_info *node) free_node_attrs(device_node_info *node)
@@ -93,16 +119,14 @@ free_node_resources(device_node_info *node)
static void static void
free_node(device_node_info *node) free_node(device_node_info *node)
{ {
const char *generator_name, *driver_name, *type; const char *generator_name, *driver_name;
uint32 auto_id; uint32 auto_id;
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK) // ToDo: we lose memory here if the attributes are available!
if (pnp_get_attr_string_nolock(node, B_DRIVER_MODULE, &driver_name, false) != B_OK)
driver_name = "?"; driver_name = "?";
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_TYPE, &type, false) != B_OK) TRACE(("free_node(node: %p, driver: %s)\n", node, driver_name));
type = "?";
TRACE(("free_node(node: %p, driver: %s, type: %s)\n", node, driver_name, type));
// free associated auto ID, if requested // free associated auto ID, if requested
if (pnp_get_attr_string_nolock(node, PNP_MANAGER_ID_GENERATOR, if (pnp_get_attr_string_nolock(node, PNP_MANAGER_ID_GENERATOR,
@@ -110,13 +134,10 @@ free_node(device_node_info *node)
if (pnp_get_attr_uint32(node, PNP_MANAGER_AUTO_ID, &auto_id, false) != B_OK) { if (pnp_get_attr_uint32(node, PNP_MANAGER_AUTO_ID, &auto_id, false) != B_OK) {
TRACE(("Cannot find corresponding auto_id of generator %s", generator_name)); TRACE(("Cannot find corresponding auto_id of generator %s", generator_name));
} else } else
pnp_free_id(generator_name, auto_id); dm_free_id(generator_name, auto_id);
} }
pnp_release_node_resources(node); dm_release_node_resources(node);
//list_remove_link(node);
REMOVE_DL_LIST( node, gNodeList, );
delete_sem(node->hook_sem); delete_sem(node->hook_sem);
delete_sem(node->load_block_sem); delete_sem(node->load_block_sem);
@@ -127,55 +148,6 @@ free_node(device_node_info *node)
} }
// remove node reference and clean it up if necessary
// (node_lock must be hold)
void
pnp_remove_node_ref_nolock(device_node_info *node)
{
do {
device_node_info *parent;
TRACE(("pnp_remove_node_ref_internal(ref_count of %p: %ld)\n", node, node->ref_count - 1));
// unregistered devices loose their I/O resources as soon as they
// are unloaded
if (!node->registered && node->loading == 0 && node->load_count == 0)
pnp_release_node_resources(node);
if (--node->ref_count > 0)
return;
TRACE(("cleaning up %p (parent: %p)\n", node, node->parent));
// time to clean up
parent = node->parent;
if (parent != NULL)
// list_remove_item(&parent->children, node);
REMOVE_DL_LIST(node, parent->children, siblings_ );
free_node(node);
// unrolled recursive call: decrease ref_count of parent as well
node = parent;
} while (node != NULL);
}
// remove node reference and clean it up if necessary
void
pnp_remove_node_ref(device_node_info *node)
{
TRACE(("pnp_remove_node_ref(%p)\n", node));
benaphore_lock(&gNodeLock);
pnp_remove_node_ref_nolock(node);
benaphore_unlock(&gNodeLock);
}
// copy node attributes into node's attribute list // copy node attributes into node's attribute list
static status_t static status_t
@@ -237,18 +209,21 @@ allocate_node_resource_array(device_node_info *node, const io_resource_handle *r
} }
// allocate device node info structure; // #pragma mark -
// initially, ref_count is one to make sure node won't get destroyed by mistake // Device Manager private functions
/** allocate device node info structure;
* initially, ref_count is one to make sure node won't get destroyed by mistake
*/
status_t status_t
pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources, dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
device_node_info **new_node) device_node_info **_node)
{ {
device_node_info *node; device_node_info *node;
status_t res; status_t res;
TRACE(("pnp_alloc_node()\n"));
node = calloc(1, sizeof(*node)); node = calloc(1, sizeof(*node));
if (node == NULL) if (node == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -269,11 +244,16 @@ pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
if (res < 0) if (res < 0)
goto err4; goto err4;
list_init(&node->children);
node->parent = NULL; node->parent = NULL;
node->rescan_depth = 0; node->rescan_depth = 0;
node->registered = false;
#if 0
node->verifying = false; node->verifying = false;
node->redetected = false; node->redetected = false;
node->init_finished = false; node->init_finished = false;
#endif
node->ref_count = 1; node->ref_count = 1;
node->load_count = 0; node->load_count = 0;
node->blocked_by_rescan = false; node->blocked_by_rescan = false;
@@ -283,17 +263,10 @@ pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
node->num_blocked_loads = 0; node->num_blocked_loads = 0;
node->load_block_count = 0; node->load_block_count = 0;
node->loading = 0; node->loading = 0;
node->defer_probing = 0;
node->unprobed_children = NULL;
// make public (well, almost: it's not officially registered yet) TRACE(("dm_allocate_node(): new node %p\n", node));
benaphore_lock(&gNodeLock);
ADD_DL_LIST_HEAD(node, gNodeList, ); *_node = node;
benaphore_unlock(&gNodeLock);
*new_node = node;
return B_OK; return B_OK;
@@ -309,45 +282,91 @@ err:
} }
// create links to parent node
void void
pnp_create_node_links(device_node_info *node, device_node_info *parent) dm_add_child_node(device_node_info *parent, device_node_info *node)
{ {
TRACE(("pnp_create_node_links(%p, parent=%p)\n", node, parent)); TRACE(("dm_add_child_node(parent = %p, child = %p)\n", parent, node));
if (parent == NULL) if (parent == NULL)
return; return;
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
TRACE(("Adding parent link")); // parent must not be destroyed as long as it has children
// parent must not be destroyed
parent->ref_count++; parent->ref_count++;
node->parent = parent; node->parent = parent;
// tell parent about us, so we get unregistered automatically if parent // tell parent about us, so we get unregistered automatically if parent
// gets unregistered // gets unregistered
ADD_DL_LIST_HEAD(node, parent->children, siblings_ ); list_add_item(&parent->children, node);
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
} }
// public: get parent of node void
dm_get_node_nolock(device_node_info *node)
device_node_handle
pnp_get_parent(device_node_handle node)
{ {
return node->parent; node->ref_count++;
} }
// increase ref_count of node
void
dm_get_node(device_node_info *node)
{
TRACE(("dm_get_device_node(%p)\n", node));
if (node == NULL)
return;
benaphore_lock(&gNodeLock);
node->ref_count++;
benaphore_unlock(&gNodeLock);
}
// remove node reference and clean it up if necessary
// (node_lock must be hold)
void
dm_put_node_nolock(device_node_info *node)
{
do {
device_node_info *parent;
TRACE(("pnp_remove_node_ref_internal(ref_count of %p: %ld)\n", node, node->ref_count - 1));
// unregistered devices lose their I/O resources as soon as they
// are unloaded
if (!node->registered && node->loading == 0 && node->load_count == 0)
dm_release_node_resources(node);
if (--node->ref_count > 0)
return;
TRACE(("cleaning up %p (parent: %p)\n", node, node->parent));
// time to clean up
parent = node->parent;
if (parent != NULL)
list_remove_item(&parent->children, node);
free_node(node);
// unrolled recursive call: decrease ref_count of parent as well
node = parent;
} while (node != NULL);
}
#if 0
// public: find node with some node attributes given // public: find node with some node attributes given
device_node_info * device_node_info *
pnp_find_device(device_node_info *parent, const device_attr *attrs) dm_find_device(device_node_info *parent, const device_attr *attrs)
{ {
device_node_info *node, *found_node; device_node_info *node, *found_node;
@@ -366,58 +385,8 @@ pnp_find_device(device_node_info *parent, const device_attr *attrs)
continue; continue;
for (attr = attrs; attr && attr->name; ++attr) { for (attr = attrs; attr && attr->name; ++attr) {
bool equal = true; device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
switch (attr->type) {
case B_UINT8_TYPE: {
uint8 value;
equal = pnp_get_attr_uint8_nolock( node, attr->name, &value, false ) == B_OK
&& value == attr->value.ui8;
break;
}
case B_UINT16_TYPE: {
uint16 value;
equal = pnp_get_attr_uint16_nolock( node, attr->name, &value, false ) == B_OK
&& value == attr->value.ui16;
break;
}
case B_UINT32_TYPE: {
uint32 value;
equal = pnp_get_attr_uint32_nolock( node, attr->name, &value, false ) == B_OK
&& value == attr->value.ui32;
break;
}
case B_UINT64_TYPE: {
uint64 value;
equal = pnp_get_attr_uint64_nolock( node, attr->name, &value, false ) == B_OK
&& value == attr->value.ui64;
break;
}
case B_STRING_TYPE: {
const char *str;
equal = pnp_get_attr_string_nolock( node, attr->name, &str, false ) == B_OK
&& strcmp( str, attr->value.string ) == 0;
break;
}
case B_RAW_TYPE: {
const void *data;
size_t len;
equal = pnp_get_attr_raw_nolock( node, attr->name, &data, &len, false ) == B_OK
&& len == attr->value.raw.len
&& !memcmp(data, attr->value.raw.data, len);
break;
}
default:
goto err;
}
if (!equal)
break; break;
} }
@@ -439,52 +408,14 @@ err:
return found_node; return found_node;
} }
#endif
static void
put_level(int32 level)
{
while (level-- > 0)
dprintf(" ");
}
static void
dump_attribute(device_attr_info *attr, int32 level)
{
if (attr == NULL)
return;
put_level(level + 2);
dprintf("\"%s\" : ", attr->attr.name);
switch (attr->attr.type) {
case B_STRING_TYPE:
dprintf("string : \"%s\"", attr->attr.value.string);
break;
case B_UINT8_TYPE:
dprintf("uint8 : %u (%#x)", attr->attr.value.ui8, attr->attr.value.ui8);
break;
case B_UINT16_TYPE:
dprintf("uint16 : %u (%#x)", attr->attr.value.ui16, attr->attr.value.ui16);
break;
case B_UINT32_TYPE:
dprintf("uint32 : %lu (%#lx)", attr->attr.value.ui32, attr->attr.value.ui32);
break;
case B_UINT64_TYPE:
dprintf("uint64 : %Lu (%#Lx)", attr->attr.value.ui64, attr->attr.value.ui64);
break;
default:
dprintf("raw data");
}
dprintf("\n");
dump_attribute(attr->next, level);
}
void void
dump_device_node_info(device_node_info *node, int32 level) dm_dump_node(device_node_info *node, int32 level)
{ {
device_node_info *child = NULL;
if (node == NULL) if (node == NULL)
return; return;
@@ -492,14 +423,78 @@ dump_device_node_info(device_node_info *node, int32 level)
dprintf("(%ld) @%p \"%s\"\n", level, node, node->driver ? node->driver->info.name : "---"); dprintf("(%ld) @%p \"%s\"\n", level, node, node->driver ? node->driver->info.name : "---");
dump_attribute(node->attributes, level); dump_attribute(node->attributes, level);
dump_device_node_info(node->children, level + 1); while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
dump_device_node_info(node->siblings_next, level); dm_dump_node(child, level + 1);
}
} }
status_t status_t
nodes_init(void) dm_init_nodes(void)
{ {
return benaphore_init(&gNodeLock, "device nodes"); return benaphore_init(&gNodeLock, "device nodes");
} }
// #pragma mark -
// Functions part of the module API
/** remove node reference and clean it up if necessary */
void
dm_put_node(device_node_info *node)
{
TRACE(("dm_put_node(%p)\n", node));
benaphore_lock(&gNodeLock);
dm_put_node_nolock(node);
benaphore_unlock(&gNodeLock);
}
device_node_info *
dm_get_parent(device_node_info *node)
{
dm_get_node(node->parent);
return node->parent;
}
status_t
dm_get_next_child_node(device_node_info *parent, device_node_info **_node,
const device_attr *attrs)
{
device_node_info *node = *_node;
if (node != NULL)
dm_put_node(node);
benaphore_lock(&gNodeLock);
while ((node = (device_node_info *)list_get_next_item(&parent->children, node)) != NULL) {
const device_attr *attr;
// list contains removed devices too, so skip them
if (!node->registered)
continue;
for (attr = attrs; attr && attr->name; ++attr) {
device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
break;
}
if (attr != NULL && attr->name != NULL)
continue;
// we found a node
dm_get_node_nolock(node);
*_node = node;
benaphore_unlock(&gNodeLock);
return B_OK;
}
benaphore_unlock(&gNodeLock);
return B_ENTRY_NOT_FOUND;
}
@@ -28,41 +28,10 @@
#endif #endif
/** notify a consumer that a device he might handle is added
* consumer_name - module name (!) of consumer
*/
status_t
pnp_notify_probe_by_module(device_node_info *node, const char *consumerName)
{
driver_module_info *consumer;
status_t status;
TRACE(("pnp_notify_probe_by_module(node %p, consumer: %s)\n", node, consumerName));
status = get_module(consumerName, (module_info **)&consumer);
if (status < B_OK) {
dprintf("Cannot load driver module %s (%s)\n", consumerName, strerror(status));
return status;
}
if (consumer->register_device == NULL) {
dprintf("Driver %s has no register_device() hook\n", consumerName);
status = B_ERROR;
} else {
status = consumer->register_device(node);
TRACE(("Driver %s register_device() returned: %s\n", consumerName, strerror(status)));
}
put_module(consumerName);
return status;
}
/** notify driver that it's device got removed */ /** notify driver that it's device got removed */
static status_t status_t
notify_device_removed(device_node_info *node) dm_notify_unregistration(device_node_info *node)
{ {
driver_module_info *driver; driver_module_info *driver;
bool loaded; bool loaded;
@@ -70,19 +39,21 @@ notify_device_removed(device_node_info *node)
void *cookie; void *cookie;
status_t res; status_t res;
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false); res = pnp_get_attr_string(node, B_DRIVER_MODULE, &module_name, false);
if (res != B_OK) if (res != B_OK)
return res; return res;
TRACE(("notify_device_removed(node: %p, consumer: %s)\n", node, module_name)); TRACE(("notify_device_removed(node: %p, consumer: %s)\n", node, module_name));
// block concurrent load/unload calls // block concurrent load/unload calls
pnp_start_hook_call(node); pnp_start_hook_call(node);
#if 0
// don't notify driver if it doesn't know that the device was // don't notify driver if it doesn't know that the device was
// published // published
if (!node->init_finished) if (!node->init_finished)
goto skip; goto skip;
#endif
// don't take node->loading into account - we want to know // don't take node->loading into account - we want to know
// whether driver is loaded, not whether it is about to get loaded // whether driver is loaded, not whether it is about to get loaded
@@ -132,20 +103,6 @@ err:
} }
/** notify all drivers in <notify_list> that their node got removed */
void
pnp_notify_unregistration(device_node_info *notify_list)
{
device_node_info *node;
TRACE(("pnp_notify_unregistration()\n"));
for (node = notify_list; node; node = node->notify_next)
notify_device_removed(node);
}
/** start driver hook call; must be called before a /** start driver hook call; must be called before a
* load/unload/notification hook is called * load/unload/notification hook is called
*/ */
+572 -119
View File
@@ -44,8 +44,16 @@ struct path_entry {
char *path; char *path;
dev_t device; dev_t device;
ino_t node; ino_t node;
int32 busses;
}; };
struct module_entry {
struct list_link link;
char *name;
driver_module_info *driver;
float support;
bool no_connection;
};
// list of driver registration directories // list of driver registration directories
const char *pnp_registration_dirs[2] = { const char *pnp_registration_dirs[2] = {
@@ -62,6 +70,8 @@ static const char *kModulePaths[] = {
NULL NULL
}; };
extern dev_t gBootDevice;
// from fs/vfs.cpp
class DirectoryIterator { class DirectoryIterator {
public: public:
@@ -207,6 +217,136 @@ DirectoryIterator::AddPath(const char *basePath, const char *subPath)
// #pragma mark - // #pragma mark -
struct path_entry *
new_path_entry(const char *path, dev_t device, ino_t node)
{
path_entry *entry = (path_entry *)malloc(sizeof(path_entry));
if (entry == NULL)
return NULL;
entry->path = strdup(path);
if (entry->path == NULL) {
free(entry);
return NULL;
}
entry->device = device;
entry->node = node;
entry->busses = 0;
return entry;
}
struct path_entry *
copy_path_entry(path_entry *entry)
{
path_entry *newEntry = (path_entry *)malloc(sizeof(struct path_entry));
if (newEntry == NULL)
return NULL;
*newEntry = *entry;
newEntry->path = strdup(entry->path);
if (newEntry->path == NULL) {
free(newEntry);
return NULL;
}
return newEntry;
}
void
free_module_entry(module_entry *entry)
{
if (entry->name != NULL && entry->driver != NULL)
put_module(entry->name);
free(entry->name);
free(entry);
}
struct module_entry *
new_module_entry(const char *name, driver_module_info *driver)
{
module_entry *entry = (module_entry *)malloc(sizeof(module_entry));
if (entry == NULL)
return NULL;
entry->name = strdup(name);
if (entry->name == NULL) {
free(entry);
return NULL;
}
entry->driver = driver;
entry->support = -1.0f;
entry->no_connection = false;
return entry;
}
static module_entry *
find_module_entry(struct list *list, const char *name)
{
module_entry *entry = NULL;
while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) {
if (!strcmp(entry->name, name))
return entry;
}
return NULL;
}
static status_t
add_device_node(struct list *list, device_node_info *node)
{
node_entry *entry = (node_entry *)malloc(sizeof(node_entry));
if (entry == NULL)
return B_NO_MEMORY;
entry->node = node;
uint8 exploreLast = false;
pnp_get_attr_uint8(node, B_DRIVER_EXPLORE_LAST, &exploreLast, false);
if (exploreLast)
list_add_link_to_tail(list, &entry->link);
else
list_add_link_to_head(list, &entry->link);
return B_OK;
}
static status_t
get_next_device_node(struct list *list, uint32 *_cookie, device_node_info **_node)
{
node_entry *entry = (node_entry *)list_get_next_item(list, (void *)*_cookie);
if (entry == NULL)
return B_ENTRY_NOT_FOUND;
*_node = entry->node;
*_cookie = (uint32)entry;
return B_OK;
}
static void
remove_device_nodes(struct list *list)
{
struct node_entry *entry;
while ((entry = (node_entry *)list_remove_head_item(list)) != NULL) {
free(entry);
}
}
#if 0
/** notify a consumer that a device he might handle is added /** notify a consumer that a device he might handle is added
* fileName - file name of consumer * fileName - file name of consumer
* (moved to end of file to avoid inlining) * (moved to end of file to avoid inlining)
@@ -271,7 +411,7 @@ notify_probe_by_file(device_node_info *node, const char *fileName)
strlcat(module_name, "/", B_PATH_NAME_LENGTH); strlcat(module_name, "/", B_PATH_NAME_LENGTH);
strlcat(module_name, type, B_PATH_NAME_LENGTH); strlcat(module_name, type, B_PATH_NAME_LENGTH);
res = pnp_notify_probe_by_module(node, module_name); res = dm_register_child_device(node, module_name);
err2: err2:
free(resolved_path); free(resolved_path);
@@ -391,14 +531,14 @@ try_drivers(device_node_info *node, char *directory,
} }
/** find normal consumer of node that are stored under <dir>; first, we /** find normal child of node that are stored under <dir>; first, we
* look for a specific driver; if none could be found, find a generic * look for a specific driver; if none could be found, find a generic
* one path, buffer - used as scratch buffer (all of size B_PATH_NAME_LENGTH + 1) * one path, buffer - used as scratch buffer (all of size B_PATH_NAME_LENGTH + 1)
* return: B_NAME_NOT_FOUND if no consumer could be found * return: B_NAME_NOT_FOUND if no consumer could be found
*/ */
static status_t static status_t
find_normal_consumer(device_node_info *node, const char *dir, find_normal_child(device_node_info *node, const char *dir,
const char *filename_pattern, int num_parts, const char *filename_pattern, int num_parts,
char *path, char *buffer, bool *found_normal_driver) char *path, char *buffer, bool *found_normal_driver)
{ {
@@ -465,7 +605,7 @@ find_normal_consumer(device_node_info *node, const char *dir,
} }
/** pre-process dynamic consumer name pattern. /** pre-process dynamic child name pattern.
* split into directory and pattern and count split positions; * split into directory and pattern and count split positions;
* further, remove quotes from directory * further, remove quotes from directory
* pattern - pattern of consumer name * pattern - pattern of consumer name
@@ -476,7 +616,7 @@ find_normal_consumer(device_node_info *node, const char *dir,
*/ */
static status_t static status_t
preprocess_consumer_names(const char *pattern, char *buffer, preprocess_child_names(const char *pattern, char *buffer,
char **filename_pattern, int *const num_parts) char **filename_pattern, int *const num_parts)
{ {
char *str, *dest; char *str, *dest;
@@ -547,7 +687,7 @@ preprocess_consumer_names(const char *pattern, char *buffer,
*/ */
static status_t static status_t
notify_dynamic_consumer(device_node_info *node, const char *bus, register_dynamic_child_device(device_node_info *node, const char *bus,
const char *pattern, bool *has_normal_driver) const char *pattern, bool *has_normal_driver)
{ {
status_t status; status_t status;
@@ -555,7 +695,7 @@ notify_dynamic_consumer(device_node_info *node, const char *bus,
char *filename_pattern; char *filename_pattern;
int num_parts; int num_parts;
TRACE(("notify_dynamic_consumer(bus = %s, pattern = %s, has_normal_driver = %d)\n", TRACE(("register_dynamic_child_device(bus = %s, pattern = %s, has_normal_driver = %d)\n",
bus, pattern, *has_normal_driver)); bus, pattern, *has_normal_driver));
if (pattern == NULL) if (pattern == NULL)
@@ -566,14 +706,14 @@ notify_dynamic_consumer(device_node_info *node, const char *bus,
if (buffers == NULL) if (buffers == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
status = preprocess_consumer_names(pattern, buffers + 2 * (B_PATH_NAME_LENGTH + 1), status = preprocess_child_names(pattern, buffers + 2 * (B_PATH_NAME_LENGTH + 1),
&filename_pattern, &num_parts); &filename_pattern, &num_parts);
if (status < B_OK) if (status < B_OK)
goto err; goto err;
if (!*has_normal_driver) { if (!*has_normal_driver) {
// find specific/generic consumer // find specific/generic consumer
status = find_normal_consumer(node, bus, filename_pattern, num_parts, status = find_normal_child(node, bus, filename_pattern, num_parts,
buffers, buffers + B_PATH_NAME_LENGTH + 1, has_normal_driver); buffers, buffers + B_PATH_NAME_LENGTH + 1, has_normal_driver);
if (status != B_OK && status != B_NAME_NOT_FOUND) if (status != B_OK && status != B_NAME_NOT_FOUND)
// only abort if there was a "real" problem; // only abort if there was a "real" problem;
@@ -600,6 +740,7 @@ err:
free(buffers); free(buffers);
return status; return status;
} }
#endif
static path_entry * static path_entry *
@@ -639,19 +780,22 @@ load_driver(const char *path)
name++; name++;
// For a valid device driver the following exports are required // For a valid device driver the following exports are required
uint32 *api_version;
if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, (void **)&api_version) != B_OK)
dprintf("%s: api_version missing\n", name);
device_hooks *(*find_device)(const char *); device_hooks *(*find_device)(const char *);
const char **(*publish_devices)(void); const char **(*publish_devices)(void);
uint32 *api_version;
if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, (void **)&publish_devices) != B_OK if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, (void **)&publish_devices) != B_OK
|| get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, (void **)&api_version) != B_OK
|| get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, (void **)&find_device) != B_OK) { || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, (void **)&find_device) != B_OK) {
dprintf("%s: mandatory driver symbol(s) missing!\n", name); dprintf("%s: mandatory driver symbol(s) missing!\n", name);
status = B_BAD_VALUE; status = B_BAD_VALUE;
goto error1; goto error1;
} }
// test for init_hardware() and call it // Init the driver
if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT,
(void **)&init_hardware) == B_OK (void **)&init_hardware) == B_OK
&& (status = init_hardware()) != B_OK) { && (status = init_hardware()) != B_OK) {
@@ -660,19 +804,6 @@ load_driver(const char *path)
goto error1; goto error1;
} }
/* OK, so we now have what appears to be a valid module that has
* completed init_hardware and thus thinks it should be used.
* ToDo:
* - this is bogus!
* - the driver init routines should be called by devfs and
* only when the driver is first needed. However, that level
* level of support is not yet in devfs, so we have a hack
* here that calls the init_driver function at this point.
* As a result we will check to see if we actually manage to
* publish the device, and if we do we will keep the module
* loaded.
* - remove this when devfs is fixed!
*/
if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT,
(void **)&init_driver) == B_OK (void **)&init_driver) == B_OK
&& (status = init_driver()) != B_OK) { && (status = init_driver()) != B_OK) {
@@ -681,7 +812,13 @@ load_driver(const char *path)
goto error2; goto error2;
} }
// The driver has successfully been initialized, now we can
// finally publish its device entries
// we keep the driver loaded if it exports at least a single interface // we keep the driver loaded if it exports at least a single interface
// ToDo: we could/should always unload drivers until they will be used for real
// ToDo: this function is probably better kept in devfs, so that it could remember
// the driver stuff (and even keep it loaded if there is enough memory)
devicePaths = publish_devices(); devicePaths = publish_devices();
if (devicePaths == NULL) { if (devicePaths == NULL) {
dprintf("%s: publish_devices() returned NULL.\n", name); dprintf("%s: publish_devices() returned NULL.\n", name);
@@ -702,7 +839,6 @@ load_driver(const char *path)
status = B_ERROR; // whatever... status = B_ERROR; // whatever...
error3: error3:
{ {
status_t (*uninit_driver)(void); status_t (*uninit_driver)(void);
@@ -712,12 +848,12 @@ error3:
} }
error2: error2:
{ {
status_t (*uninit_hardware)(void); status_t (*uninit_hardware)(void);
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
(void **)&uninit_hardware) == B_OK) (void **)&uninit_hardware) == B_OK)
uninit_hardware(); uninit_hardware();
} }
error1: error1:
/* If we've gotten here then the driver will be unloaded and an /* If we've gotten here then the driver will be unloaded and an
* error code returned. * error code returned.
@@ -740,11 +876,25 @@ load_driver_symbols(const char *driverName)
} }
/** Iterates over the given list and tries to load all drivers and modules
* in that list.
* The list is emptied and freed during the traversal.
*
* ToDo: Old style drivers will be initialized as well, new style driver
* handling is not yet done.
*/
static status_t static status_t
try_drivers(struct list &list) try_drivers(struct list &list, bool tryBusDrivers)
{ {
path_entry *entry; path_entry *entry;
while ((entry = (path_entry *)list_remove_head_item(&list)) != NULL) { while ((entry = (path_entry *)list_remove_head_item(&list)) != NULL) {
if (!tryBusDrivers && entry->busses) {
free(entry->path);
free(entry);
continue;
}
image_id image = load_kernel_add_on(entry->path); image_id image = load_kernel_add_on(entry->path);
if (image >= 0) { if (image >= 0) {
// check if it's a driver module // check if it's a driver module
@@ -771,127 +921,393 @@ try_drivers(struct list &list)
} }
static module_entry *
remove_best_entry(struct list *list)
{
module_entry *bestEntry = NULL;
module_entry *entry = NULL;
while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) {
if (entry->no_connection || entry->driver == NULL
|| entry->driver->register_device == NULL
|| entry->support <= 0.0)
continue;
if (bestEntry == NULL || bestEntry->support < entry->support)
bestEntry = entry;
}
if (bestEntry) {
list_remove_item(list, bestEntry);
return bestEntry;
}
return NULL;
}
static void
register_supporting_child_devices(device_node_info *node, struct list *list)
{
// See if this node has a connection to offer
char *hasConnection = NULL;
// this is a bit ugly as we don't access the string
// but just test it against NULL
if (pnp_get_attr_string(node, PNP_DRIVER_CONNECTION, &hasConnection, false) == B_OK)
free(hasConnection);
dprintf("has connection? %s\n", hasConnection ? "yes" : "no");
// first ask each module for level of support
module_entry *bestEntry = NULL;
module_entry *entry = NULL;
while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) {
if (entry->driver == NULL) {
if (get_module(entry->name, (module_info **)&entry->driver) != B_OK)
continue;
}
entry->support = entry->driver->supports_device(node, &entry->no_connection);
dprintf("module: %s, support: %d\n", entry->name, (int)(entry->support * 1000));
if (!hasConnection)
entry->no_connection = true;
}
// register best module with a connection
while ((entry = remove_best_entry(list)) != NULL) {
status_t status = entry->driver->register_device(node);
dprintf("tried best module: %s: %s\n", entry->name, strerror(status));
free_module_entry(entry);
if (status == B_OK)
break;
}
// register all modules that don't need a connection
// and empty the list
while ((entry = (module_entry *)list_remove_head_item(list)) != NULL) {
if (entry->no_connection && entry->driver != NULL
&& entry->driver->register_device != NULL
&& entry->support > 0.0) {
dprintf("register rest: %s\n", entry->name);
entry->driver->register_device(node);
}
dprintf("free %s\n", entry->name);
free_module_entry(entry);
}
}
static bool
is_driver_module(const char *name, int32 length)
{
if (length == -1)
length = strlen(name);
return !strcmp(name + length - 9, "device_v1");
}
static status_t
get_loaded_modules(struct list *modules, const char *bus, const char *device)
{
TRACE(("get_loaded_modules(bus = %s, device = %s)\n", bus, device));
bool listWasEmpty = list_is_empty(modules);
char name[B_FILE_NAME_LENGTH];
size_t size = sizeof(name);
uint32 cookie = 0;
while (get_next_loaded_module_name(&cookie, name, &size) == B_OK) {
int32 length = size;
size = sizeof(name);
if (!is_driver_module(name, length))
continue;
TRACE((" \"%s\" is driver module!\n", name));
driver_module_info *info;
if (get_module(name, (module_info **)&info) == B_OK) {
if (info->get_supported_paths == NULL)
continue;
const char **busses, **devices;
info->get_supported_paths(&busses, &devices);
bool support = bus == NULL;
// search for the bus
if (bus != NULL && busses != NULL) {
for (int32 i = 0; busses[i]; i++) {
if (!strcmp(bus, busses[i])) {
dprintf("\tfound %s!!\n", busses[i]);
support = true;
break;
}
}
}
if (support) {
// search for the device
support = device == NULL;
if (device != NULL && devices != NULL) {
for (int32 i = 0; devices[i]; i++) {
if (!strncmp(device, devices[i], strlen(device))) {
dprintf("\tfound %s!!\n", devices[i]);
support = true;
break;
}
}
}
}
if (support && !listWasEmpty) {
// make sure we don't add the same module twice
if (find_module_entry(modules, name) != NULL)
support = false;
}
if (support) {
module_entry *entry = new_module_entry(name, info);
if (entry == NULL) {
put_module(name);
return B_NO_MEMORY;
}
dprintf("\tadd module %s to list\n", name);
list_add_item(modules, entry);
continue;
}
put_module(name);
}
}
return B_OK;
}
static status_t
get_nodes_for_device_type(device_node_info *node, struct list *list, const char *type)
{
bool matches = false;
// see if there is a B_DRIVER_DEVICE_TYPE that matches the query
char *deviceType = NULL;
if (pnp_get_attr_string(node, B_DRIVER_DEVICE_TYPE, &deviceType, false) == B_OK) {
if (!strncmp(deviceType, type, strlen(type)))
matches = true;
free(deviceType);
}
if (!matches) {
// we also accept any dump busses
uint8 onDemand = false;
pnp_get_attr_uint8(node, B_DRIVER_FIND_DEVICES_ON_DEMAND, &onDemand, false);
if (onDemand)
matches = true;
}
if (matches) {
dprintf("** NODE MATCHES TYPE %s\n", type);
dm_dump_node(node, 0);
return add_device_node(list, node);
}
// search child nodes, then
device_node_info *child = NULL;
while (dm_get_next_child_node(node, &child, NULL) == B_OK) {
status_t status = get_nodes_for_device_type(child, list, type);
if (status != B_OK) {
dm_put_node(child);
return status;
}
}
return B_OK;
}
// #pragma mark - // #pragma mark -
// device manager private API // device manager private API
/** Register the device of a child for the \a node that might accept it.
* childName - module name of child/consumer
*/
status_t
dm_register_child_device(device_node_info *node, const char *childName)
{
driver_module_info *child;
status_t status;
TRACE(("dm_register_child_device(node = %p, child = %s)\n", node, childName));
status = get_module(childName, (module_info **)&child);
if (status < B_OK) {
dprintf("Cannot load driver module %s (%s)\n", childName, strerror(status));
return status;
}
if (child->register_device != NULL) {
status = child->register_device(node);
if (status != B_OK) {
TRACE(("dm_register_child_device(): Driver %s returned: %s\n",
childName, strerror(status)));
}
} else {
dprintf("Driver %s has no register_device() hook\n", childName);
status = B_ERROR;
}
put_module(childName);
return status;
}
/** find and notify dynamic consumers that device was added /** find and notify dynamic consumers that device was added
* errors returned by consumers aren't reported, only problems * errors returned by consumers aren't reported, only problems
* like malformed consumer patterns * like malformed consumer patterns
*/ */
status_t status_t
pnp_notify_dynamic_consumers(device_node_info *node) dm_register_dynamic_child_devices(device_node_info *node)
{ {
#if 0
char *buffer; char *buffer;
char *bus; char *bus;
status_t status = B_OK; status_t status = B_OK;
int32 i, found = 0; int32 i, found = 0;
TRACE(("pnp_notify_dynamic_consumers(node = %p)\n", node)); TRACE(("dm_register_dynamic_child_devices(node = %p)\n", node));
if (pnp_get_attr_string(node, PNP_DRIVER_CONSUMER_BUS, &bus, false) != B_OK) if (pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false) != B_OK)
return B_OK; return B_OK;
TRACE((" Search bus: \"%s\"\n", bus)); TRACE((" Search bus: \"%s\"\n", bus));
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1); if (gBootDevice < 0) {
if (buffer == NULL) { // there is no boot device yet, we have to scan the already
status = B_NO_MEMORY; // loaded and built-in modules
goto err; struct list modules;
} list_init(&modules);
// first, append nothing, then "/0", "/1" etc. status = get_loaded_modules(&modules, bus, NULL);
for (i = -1; ; ++i) { if (status != B_OK)
bool noSpecificDriver = false; return status;
char *consumer;
strcpy(buffer, PNP_DRIVER_CONSUMER_MAPPING); register_supporting_child_devices(node, &modules);
if (i >= 0) return B_OK;
sprintf(buffer + strlen( buffer ), "/%ld", i); } else {
// ToDo: this is completely outdated and must be redone!
status = B_ERROR;
#if 0
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
if (buffer == NULL) {
status = B_NO_MEMORY;
goto err;
}
// if no more dynamic consumers, cancel loop silently // first, append nothing, then "/0", "/1" etc.
if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) { for (i = -1; ; ++i) {
// starting with .../0 is OK, so ignore error if i = -1 bool noSpecificDriver = false;
if (i == -1) char *consumer;
continue;
else strcpy(buffer, B_DRIVER_MAPPING);
if (i >= 0)
sprintf(buffer + strlen( buffer ), "/%ld", i);
// if no more dynamic consumers, cancel loop silently
if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) {
// starting with .../0 is OK, so ignore error if i = -1
if (i == -1)
continue;
else
break;
}
TRACE((" Consumer pattern %ld: %s\n", i, consumer));
status = register_dynamic_child_device(node, bus, consumer, &noSpecificDriver);
free(consumer);
found++;
if (status != B_OK) {
// this is only reached if a serious error occured,
// see register_dynamic_child_device()
break; break;
}
} }
#endif
TRACE((" Consumer pattern %ld: %s\n", i, consumer));
status = notify_dynamic_consumer(node, bus, consumer, &noSpecificDriver);
free(consumer);
found++;
if (status != B_OK) {
// this is only reached if a serious error occured,
// see notify_dynamic_consumer()
break;
}
} }
#if 0
if (found == 0) { if (found == 0) {
// no requirement for a special mapping, so we're just scanning the bus directory // no requirement for a special mapping, so we're just scanning the bus directory
bool noSpecificDriver = false; bool noSpecificDriver = false;
status = notify_dynamic_consumer(node, bus, NULL, &noSpecificDriver); status = register_dynamic_child_device(node, bus, NULL, &noSpecificDriver);
} }
// supposed to go through // supposed to go through
free(buffer); free(buffer);
#endif
err: err:
free(bus); free(bus);
return status; return status;
#else
return B_OK;
#endif
} }
/** Notify fixed consumers that device was added; in contrast to dynamic /** Register all fixed child devices of of the given \a node; in contrast
* consumers, errors reported by fixed consumers are not ignored but * to dynamic child devices, errors reported by fixed child devices are
* returned. * not ignored but returned, and regarded critical.
*/ */
status_t status_t
pnp_notify_fixed_consumers(device_node_info *node) dm_register_fixed_child_devices(device_node_info *node)
{ {
int i; TRACE(("dm_register_fixed_child_devices(node = %p)\n", node));
char *buffer;
TRACE(("pnp_notify_fixed_consumers(node = %p)\n", node)); char *buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
if (buffer == NULL) if (buffer == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
// first, append nothing, then "/0", "/1" etc. // first, append nothing, then "/0", "/1" etc.
for (i = -1; ; ++i) { for (int32 i = -1; ; ++i) {
char *consumer; char *childName;
strcpy(buffer, PNP_DRIVER_FIXED_CONSUMER); strcpy(buffer, B_DRIVER_FIXED_CHILD);
if (i >= 0) if (i >= 0)
sprintf(buffer + strlen(buffer), "/%d", i); sprintf(buffer + strlen(buffer), "/%ld", i);
// if no more fixed consumers, cancel loop silently // if no more fixed consumers, cancel loop silently
if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) if (pnp_get_attr_string(node, buffer, &childName, false) != B_OK)
break; break;
TRACE(("Consumer %d: %s\n", i, consumer)); TRACE(("Consumer %ld: %s\n", i, childName));
if (pnp_notify_probe_by_module(node, consumer) != B_OK) { if (dm_register_child_device(node, childName) != B_OK) {
dprintf("Cannot notify fixed consumer %s\n", consumer); dprintf("Cannot register fixed child device %s\n", childName);
// report error if fixed consumers couldn't be loaded // report error if fixed consumers couldn't be loaded
// as they are obviously crucial (else they wouldn't be fixed) // as they are obviously crucial (else they wouldn't be fixed)
free(consumer);
// ToDo: what about the devices we already registered up to this point?
free(childName);
free(buffer); free(buffer);
return B_NAME_NOT_FOUND; return B_NAME_NOT_FOUND;
} }
free(consumer); free(childName);
} }
free(buffer); free(buffer);
@@ -899,49 +1315,65 @@ pnp_notify_fixed_consumers(device_node_info *node)
} }
status_t static status_t
probe_for_device_type(const char *type) probe_for_driver_modules(const char *type)
{ {
TRACE(("probe_for_driver_modules(type = %s)\n", type));
// search a node with an open connection of the specified type // search a node with an open connection of the specified type
// or notify bus managers to get one // or notify bus managers to get one
status_t status = B_OK; status_t status = B_OK;
// build list of potential drivers for that type
struct list drivers; struct list drivers;
list_init(&drivers); list_init(&drivers);
char devType[64]; if (gBootDevice < 0) {
snprintf(devType, sizeof(devType), "drivers/dev%s%s", type[0] ? "/" : "", type); struct list nodes;
list_init(&nodes);
DirectoryIterator iterator(kModulePaths, devType, false); get_nodes_for_device_type(gRootNode, &nodes, type);
device_node_info *node;
uint32 cookie = 0;
while (get_next_device_node(&nodes, &cookie, &node) == B_OK) {
char *bus;
if (pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false) == B_OK) {
struct list drivers;
list_init(&drivers);
get_loaded_modules(&drivers, bus, type);
register_supporting_child_devices(node, &drivers);
free(bus);
}
}
remove_device_nodes(&nodes);
return B_OK;
}
// build list of potential drivers for that type
DirectoryIterator iterator(kModulePaths, type, false);
struct stat stat; struct stat stat;
KPath path; KPath path;
while (iterator.GetNext(path, stat) == B_OK) { while (iterator.GetNext(path, stat) == B_OK) {
path_entry *entry = (path_entry *)malloc(sizeof(path_entry));
if (entry == NULL)
return B_NO_MEMORY;
entry->path = strdup(path.Path());
if (entry->path == NULL) {
free(entry);
return B_NO_MEMORY;
}
if (S_ISDIR(stat.st_mode)) { if (S_ISDIR(stat.st_mode)) {
// We need to make sure that drivers in ie. "audio/raw/" can // We need to make sure that drivers in ie. "audio/raw/" can
// be found as well - therefore, we must make sure that "audio" // be found as well - therefore, we must make sure that "audio"
// exists on /dev. // exists on /dev.
if (type[0]) int32 length = strlen("drivers/dev/");
devfs_publish_directory(type); if (!strncmp(type, "drivers/dev/", length))
devfs_publish_directory(type + length);
continue; continue;
} }
entry->device = stat.st_dev;
entry->node = stat.st_ino;
dprintf("found potential driver: %s\n", path.Path()); path_entry *entry = new_path_entry(path.Path(), stat.st_dev, stat.st_ino);
if (entry == NULL)
return B_NO_MEMORY;
TRACE(("found potential driver: %s\n", path.Path()));
list_add_item(&drivers, entry); list_add_item(&drivers, entry);
} }
@@ -959,13 +1391,23 @@ probe_for_device_type(const char *type)
struct list driversForBus; struct list driversForBus;
list_init(&driversForBus); list_init(&driversForBus);
dprintf("bus: %s\n", path.Leaf());
while (busIterator.GetNext(path, stat) == B_OK) { while (busIterator.GetNext(path, stat) == B_OK) {
path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, stat.st_ino); path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, stat.st_ino);
if (entry == NULL) if (entry == NULL)
continue; continue;
// we found the driver here, so we should check it entry->busses++;
list_remove_link(&entry->link); // mark this entry as being used by a bus
// ToDo: we don't need to remember drivers when there is no bus for them
// (ie. no need to store ISA drivers when there is no ISA bus in the system)
entry = copy_path_entry(entry);
if (entry == NULL)
continue;
list_add_item(&driversForBus, entry); list_add_item(&driversForBus, entry);
dprintf("found driver for bus \"%s\": \"%s\"\n", path.Path(), entry->path); dprintf("found driver for bus \"%s\": \"%s\"\n", path.Path(), entry->path);
} }
@@ -973,11 +1415,22 @@ probe_for_device_type(const char *type)
// ToDo: do something with the bus drivers... :) // ToDo: do something with the bus drivers... :)
// ToDo: ask bus manager for driver (via mapping) // ToDo: ask bus manager for driver (via mapping)
// ToDo: find all nodes where this driver could be attached to // ToDo: find all nodes where this driver could be attached to
try_drivers(driversForBus); try_drivers(driversForBus, true);
} }
// ToDo: do something with the remaining drivers... :) // ToDo: do something with the remaining drivers... :)
try_drivers(drivers); try_drivers(drivers, false);
return B_OK; return B_OK;
} }
status_t
probe_for_device_type(const char *type)
{
TRACE(("probe_for_device_type(type = %s)\n", type));
char deviceType[64];
snprintf(deviceType, sizeof(deviceType), "drivers/dev%s%s", type[0] ? "/" : "", type);
return probe_for_driver_modules(deviceType);
}
+140 -254
View File
@@ -29,22 +29,7 @@
#endif #endif
// decrease ref_count of unregistered nodes, specified by <node_list> /** mark node being registered, so it can be accessed via load_driver() */
void
pnp_unref_unregistered_nodes(device_node_info *node_list)
{
device_node_info *node, *next_node;
for (node = node_list; node; node = next_node) {
next_node = node->notify_next;
pnp_remove_node_ref(node);
}
}
// mark node being registered, so it can be accessed via load_driver()
static status_t static status_t
mark_node_registered(device_node_info *node) mark_node_registered(device_node_info *node)
@@ -52,7 +37,7 @@ mark_node_registered(device_node_info *node)
status_t res; status_t res;
TRACE(("mark_node_registered(%p)\n", node)); TRACE(("mark_node_registered(%p)\n", node));
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
if (node->parent && !node->parent->registered) { if (node->parent && !node->parent->registered) {
@@ -65,15 +50,15 @@ mark_node_registered(device_node_info *node)
} }
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
return res; return res;
} }
#if 0
// check whether device is redetected and remove /** Checks whether the device is redetected and removes any other
// any device that is on same connection. * device that is on same connection and has the same device identifier.
// *redetected is set true if device is already registered; * \a redetected is set true if device is already registered;
// the node must not yet be linked into parent node's children list * the node must not yet be linked into parent node's children list
*/
static status_t static status_t
is_device_redetected(device_node_info *node, device_node_info *parent, bool *redetected) is_device_redetected(device_node_info *node, device_node_info *parent, bool *redetected)
@@ -94,7 +79,7 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
} }
// we keep the lock very long, but this is the only way to be sure that // we keep the lock very long, but this is the only way to be sure that
// noone else (un)-registers a conflicting note during the tests // no one else (un)-registers a conflicting note during the tests
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
{ {
@@ -203,10 +188,10 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
if (unregister_sibling) { if (unregister_sibling) {
// increase ref_count to make sure node still exists // increase ref_count to make sure node still exists
// when node_lock has been released // when gNodeLock has been released
++sibling->ref_count; ++sibling->ref_count;
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
pnp_unregister_device(sibling); pnp_unregister_device(sibling);
pnp_remove_node_ref_nolock(sibling); pnp_remove_node_ref_nolock(sibling);
} else } else
@@ -214,283 +199,184 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
return B_OK; return B_OK;
err: err:
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
return res; return res;
} }
#endif
// postpone searching for consumers if necessary static status_t
// return: true, if postponed push_node_on_stack(struct list *list, device_node_info *node)
static bool
pnp_postpone_probing(device_node_info *node)
{ {
benaphore_lock(&gNodeLock); struct node_entry *entry = (struct node_entry *)malloc(sizeof(struct node_entry));
if (entry == NULL)
return B_NO_MEMORY;
// ask parent(!) if probing is to be postponed dm_get_node_nolock(node);
if (node->parent == NULL || !node->parent->defer_probing) { entry->node = node;
benaphore_unlock(&gNodeLock); list_add_item(list, entry);
return false; return B_OK;
}
// yes: this happens if the new node is a child of a bus node whose
// rescan has not been finished
TRACE(("postpone probing of node %p\n", node));
ADD_DL_LIST_HEAD(node, node->parent->unprobed_children, unprobed_ );
benaphore_unlock(&gNodeLock);
return true;
} }
// public: register device node. static device_node_info *
// in terms of I/O resources: if registration fails, they are freed; reason is pop_node_from_stack(struct list *list)
// that they may have been transferred to node before error and back-transferring {
// them would be complicated device_node_info *node;
struct node_entry *entry = (struct node_entry *)list_remove_head_item(list);
if (entry == NULL)
return NULL;
node = entry->node;
free(entry);
return node;
}
// #pragma mark -
// Public functions part of the module API
/** Register device node.
* In terms of I/O resources: if registration fails, they are freed; reason is
* that they may have been transferred to node before error and back-transferring
* them would be complicated.
*/
status_t status_t
pnp_register_device(device_node_handle parent, const device_attr *attrs, dm_register_node(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *io_resources, device_node_handle *node) const io_resource_handle *ioResources, device_node_handle *_node)
{ {
device_node_info *node_inf; device_node_info *newNode;
bool redetected; char *driverName = NULL;
status_t res = B_OK; status_t status = B_OK;
struct list stack;
res = pnp_alloc_node(attrs, io_resources, &node_inf); status = dm_allocate_node(attrs, ioResources, &newNode);
if (res != B_OK) if (status != B_OK) {
goto err; // always "consume" I/O resources
dm_release_io_resources(ioResources);
{ return status;
char *driver_name, *type;
if (pnp_get_attr_string(node_inf, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK) {
dprintf("Missing driver filename in node\n");
res = B_BAD_VALUE;
goto err1;
}
if (pnp_get_attr_string(node_inf, PNP_DRIVER_TYPE, &type, false) != B_OK) {
dprintf("Missing type in node registered by %s\n", driver_name);
free(driver_name);
res = B_BAD_VALUE;
goto err1;
}
TRACE(("driver: %s, type: %s\n", driver_name, type));
free(driver_name);
free(type);
} }
// check whether this device already existed and thus is redetected if (pnp_get_attr_string(newNode, B_DRIVER_MODULE, &driverName, false) != B_OK)
res = is_device_redetected(node_inf, parent, &redetected); status = B_BAD_VALUE;
if (res != B_OK)
goto err1;
if (redetected) { TRACE(("dm_register_node(driver = %s)\n", driverName));
// upon redetect, resources are released instead of transferred and
// no node is returned free(driverName);
*node = NULL;
res = B_OK; if (status != B_OK) {
goto err1; dprintf("device_manager: Missing driver module name.\n");
goto err;
} }
// transfer resources to device, unregistering all colliding devices; // transfer resources to device, unregistering all colliding devices;
// this cannot fail - we've already allocated the resource handle array // this cannot fail - we've already allocated the resource handle array
pnp_assign_io_resources(node_inf, io_resources); dm_assign_io_resources(newNode, ioResources);
pnp_create_node_links(node_inf, parent);
// make it public // make it public
res = mark_node_registered(node_inf); dm_add_child_node(parent, newNode);
if (res != B_OK)
goto err2;
// from now on, node won't get freed as ref_count has been increased by registration // The following is done to reduce the stack usage of deeply nested
// child device nodes.
// There is no other need to delay the complete registration process
// the way done here. This approach is also slightly different as
// the registration might fail later than it used in case of errors.
// check whether searching for consumers should be deferred if (parent == NULL || parent->registered) {
if (pnp_postpone_probing(node_inf)) { // register all device nodes not yet registered - build a list
// return without decrementing ref_count - else node may get // that contain all of them, and then empty it one by one (during
// lost before deferred probe // iteration, there might be new nodes added)
*node = node_inf;
return B_OK; device_node_info *node = newNode;
list_init(&stack);
push_node_on_stack(&stack, newNode);
while ((node = pop_node_from_stack(&stack)) != NULL) {
device_node_info *child = NULL;
// register all fixed child device nodes as well
status = dm_register_fixed_child_devices(node);
if (status != B_OK)
goto err2;
node->registered = true;
// and now let it register all child devices, if it's a bus
status = dm_register_child_devices(node);
if (status != B_OK)
goto err2;
// push all new nodes on the stack
benaphore_lock(&gNodeLock);
while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
if (!child->registered)
push_node_on_stack(&stack, child);
}
benaphore_unlock(&gNodeLock);
dm_put_node(node);
}
} }
res = pnp_initial_scan(node_inf); if (_node)
if (res != B_OK) *_node = newNode;
goto err2;
pnp_load_driver_automatically(node_inf, false); return B_OK;
*node = node_inf;
TRACE(("done: node=%p\n", *node));
// alloc_node has set ref_count to one for safety, correct this now
pnp_remove_node_ref(node_inf);
return res;
err2: err2:
// use this exit after i/o resources have been transferred to node {
pnp_remove_node_ref(node_inf); // nodes popped from the stack also need their reference count released
return res; device_node_info *node;
while ((node = pop_node_from_stack(&stack)) != NULL) {
err1: dm_put_node(node);
// alloc_node has set ref_count to one for safety, correct this now }
pnp_remove_node_ref(node_inf); }
err: err:
// always "consume" i/o resources // this also releases the I/O resources
pnp_release_io_resources(io_resources); dm_put_node(newNode);
return res; return status;
} }
// public: unregister device node /** Unregister device node.
* This also makes sure that all children of this node are unregistered.
*/
status_t status_t
pnp_unregister_device(device_node_info *node) dm_unregister_node(device_node_info *node)
{ {
device_node_info *dependency_list = NULL; device_node_info *child, *nextChild;
TRACE(("pnp_unregister_device(%p)\n", node)); TRACE(("pnp_unregister_device(%p)\n", node));
if (node == NULL) if (node == NULL)
return B_OK; return B_OK;
// unregistered node and all children // unregistered node and all children
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
pnp_unregister_node_rec(node, &dependency_list); if (node->parent != NULL)
list_remove_item(&node->parent->children, node);
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
pnp_unload_driver_automatically(node, false); // tell driver about their unregistration
dm_notify_unregistration(node);
// tell drivers about their unregistration // unregister children recursively
pnp_notify_unregistration(dependency_list); for (child = list_get_first_item(&node->children); child; child = nextChild) {
nextChild = (device_node_info *)child->siblings.next;
dm_unregister_node(child);
}
// now, we can safely decrease ref_count of unregistered nodes dm_put_node(node);
pnp_unref_unregistered_nodes(dependency_list);
return B_OK; return B_OK;
} }
// remove <registered> flag of node and all children.
// list of all unregistered nodes is appended to <dependency_list>;
// (node_lock must be hold)
void
pnp_unregister_node_rec(device_node_info *node, device_node_info **dependency_list)
{
device_node_info *child, *next_child;
TRACE(("pnp_unregister_node_rec(%p)\n", node));
{
const char *driver_name, *type;
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK) {
dprintf("unregister_node: Missing driver filename in node\n");
goto err;
}
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_TYPE, &type, false) != B_OK) {
dprintf("unregister_node: Missing type in node registered by %s\n", driver_name);
goto err;
}
TRACE(("driver: %s, type: %s\n", driver_name, type));
}
err:
// especially when we go through children, it can happen that they
// got unregistered already, so ignore them silently
if (!node->registered)
return;
TRACE(("Preparing unregistration\n"));
node->registered = false;
ADD_DL_LIST_HEAD(node, *dependency_list, notify_);
// unregister children recursively
for (child = node->children; child; child = next_child) {
next_child = child->siblings_next;
pnp_unregister_node_rec(child, dependency_list);
}
}
// defer probing of children.
// node_lock must be hold
void
pnp_defer_probing_of_children_nolock(device_node_info *node)
{
++node->defer_probing;
}
// defer probing of children
void
pnp_defer_probing_of_children(device_node_info *node)
{
benaphore_lock(&gNodeLock);
pnp_defer_probing_of_children_nolock(node);
benaphore_unlock(&gNodeLock);
}
// execute deferred probing of children
// (node_lock must be hold)
void
pnp_probe_waiting_children_nolock(device_node_info *node)
{
if (--node->defer_probing > 0 && node->unprobed_children != 0)
return;
TRACE(("execute deferred probing of parent %p\n", node));
while (node->unprobed_children) {
device_node_info *child = node->unprobed_children;
REMOVE_DL_LIST(child, node->unprobed_children, unprobed_);
// child may have been removed meanwhile
if (child->registered) {
benaphore_unlock(&gNodeLock);
if (pnp_initial_scan(child) == B_OK)
pnp_load_driver_automatically(node, false);
benaphore_lock(&gNodeLock);
}
// reference count was increment to keep node alive in wannabe list;
// this is not necessary anymore
pnp_remove_node_ref(node);
}
TRACE((".. done.\n"));
}
// execute deferred probing of children
void
pnp_probe_waiting_children(device_node_info *node)
{
benaphore_lock(&gNodeLock);
pnp_probe_waiting_children_nolock(node);
benaphore_unlock(&gNodeLock);
}
+18 -127
View File
@@ -29,154 +29,44 @@
#endif #endif
#define PNP_ROOT_TYPE_NAME "pnp/root" #define PNP_ROOT_MODULE_NAME "system/devices_root/driver_v1"
// type of pnp root device
#define PNP_ROOT_DRIVERS_DIR "root"
// registration directory of pnp root drivers
// (put all drivers under "universal" and use unique connection names)
#define PNP_ROOT_MODULE_NAME "sys/pnp_root/v1"
static device_node_handle sRootNode;
void void
pnp_root_init_root(void) dm_init_root_node(void)
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }}, { B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_ROOT_TYPE_NAME }}, { B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "Devices Root" }},
// well - connection is actually pointless as there is no other root node
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "pnp_root" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "pnp_root" }},
// directory for root drivers
// ToDo: temporary hack to get things started!
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "bus_managers/isa/root" }},
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string: PNP_ROOT_DRIVERS_DIR "/" }},
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "root" }},
{ NULL } { NULL }
}; };
if (pnp_register_device(NULL, attrs, NULL, &sRootNode) != B_OK) if (dm_register_node(NULL, attrs, NULL, &gRootNode) != B_OK) {
dprintf("Cannot register PnP-Root\n"); // ToDo: don't panic for now
// ToDo: don't panic for now dprintf("Cannot register Devices Root Node\n");
// panic("Cannot register PnP-Root\n"); }
}
void
pnp_root_destroy_root(void)
{
// make sure we are registered
if (sRootNode == NULL)
return;
TRACE(("Destroying PnP-root\n"));
if (pnp_unregister_device(sRootNode) != B_OK)
return;
sRootNode = NULL;
}
void
pnp_root_rescan_root(void)
{
// make sure we are registered
if (sRootNode == NULL)
return;
TRACE(("Rescanning PnP-root\n"));
// scan _very_ deep
pnp_rescan(sRootNode, 30000);
} }
static status_t static status_t
pnp_root_init_device(device_node_handle node, void *user_cookie, void **cookie) root_init_driver(device_node_handle node, void *user_cookie, void **_cookie)
{ {
*cookie = NULL; *_cookie = NULL;
return B_OK; return B_OK;
} }
static status_t static status_t
pnp_root_uninit_device(void *cookie) root_uninit_driver(void *cookie)
{ {
return B_OK; return B_OK;
} }
/*
static status_t pnp_root_device_added(
device_node_handle parent )
{
char *tmp;
status_t res;
device_node_handle loader_node;
// make sure parent is really root
if( pnp->get_attr_string( parent, PNP_DRIVER_TYPE, &tmp, false ))
return B_ERROR;
if( strcmp( tmp, PNP_ROOT_NODE_TYPE_NAME ) != 0 ) {
free( tmp );
return B_ERROR;
}
free( tmp );
// load ISA bus manager
// if you don't want ISA, remove this registration
{
device_attr attrs[] = {
// info about ourself
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: "pnp/isa_loader" }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: ISA2_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "ISA" }},
{ NULL }
};
SHOW_FLOW0( 4, "registering ISA root" );
res = pnp->register_device( parent, attrs, NULL, &loader_node );
if( res != B_OK )
return res;
}
// load PCI bus manager
{
device_attr attrs[] = {
// info about ourself
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: "pnp/pci_loader" }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PCI_ROOT_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "PCI" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "PCI" }},
{ NULL }
};
SHOW_FLOW0( 4, "registering PCI root" );
res = pnp->register_device( parent, attrs, NULL, &loader_node );
if( res != B_OK )
return res;
}
return B_OK;
}
*/
static status_t static status_t
std_ops(int32 op, ...) root_std_ops(int32 op, ...)
{ {
switch (op) { switch (op) {
case B_MODULE_INIT: case B_MODULE_INIT:
@@ -193,12 +83,13 @@ driver_module_info gDeviceRootModule = {
{ {
PNP_ROOT_MODULE_NAME, PNP_ROOT_MODULE_NAME,
0, 0,
std_ops, root_std_ops,
}, },
pnp_root_init_device, NULL, // supported devices
pnp_root_uninit_device, NULL, // register device
NULL, root_init_driver,
root_uninit_driver,
NULL, NULL,
NULL NULL
}; };
+140 -350
View File
@@ -21,7 +21,9 @@
#include "device_manager_private.h" #include "device_manager_private.h"
#include <KernelExport.h> #include <KernelExport.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#define TRACE_SCAN #define TRACE_SCAN
@@ -31,284 +33,68 @@
# define TRACE(x) ; # define TRACE(x) ;
#endif #endif
static status_t scan(device_node_info *node, bool rescan);
/** public function: rescan PnP node */
status_t static int32 sRescanning = 0;
pnp_rescan(device_node_info *node, uint32 depth)
#if 0
// execute deferred probing of children
// (node_lock must be hold)
void
pnp_probe_waiting_children_nolock(device_node_info *node)
{ {
return pnp_rescan_int(node, depth, false); TRACE(("execute deferred probing of parent %p\n", node));
while (node->unprobed_children) {
device_node_info *child = node->unprobed_children;
REMOVE_DL_LIST(child, node->unprobed_children, unprobed_);
// child may have been removed meanwhile
if (child->registered) {
benaphore_unlock(&gNodeLock);
if (pnp_initial_scan(child) == B_OK)
pnp_load_driver_automatically(node, false);
benaphore_lock(&gNodeLock);
}
// reference count was increment to keep node alive in wannabe list;
// this is not necessary anymore
pnp_remove_node_ref(node);
}
TRACE((".. done.\n"));
} }
/** execute registration of fully constructed node */ // execute deferred probing of children
status_t void
pnp_initial_scan(device_node_info *node) pnp_probe_waiting_children(device_node_info *node)
{ {
pnp_start_hook_call(node);
node->init_finished = true;
pnp_finish_hook_call(node);
return pnp_rescan_int(node, 1, false);
}
/** check whether rescanning a node makes sense in terms of
* double scans.
* node_lock must be hold
*/
static bool
is_rescan_sensible(device_node_info *node)
{
uint depth;
device_node_info *child;
TRACE(("is_rescan_sensible(node: %p)\n", node));
// if a child is being scanned, abort our rescan to avoid
// concurrent scans by the same driver on the same device
for (child = node->children; child != NULL; child = child->siblings_next) {
if (child->rescan_depth > 0) {
TRACE(("child %p is being scanned\n", child));
return false;
}
}
TRACE(("check parents\n"));
// make sure neither this nor parent node is scanned recursively
// up to this node as this would lead to unnecessary double-scans
// (don't need to check whether parent is unregistered as
// all children would have been unregistered immediately)
for (depth = 1; node != NULL; node = node->parent, ++depth) {
if (node->rescan_depth >= depth) {
TRACE(("parent %p is being scanned", node));
return false;
}
}
return true;
}
/** mark children of node as being scanned.
* children that have their drivers loaded are not
* scanned unless they allow that explicitely.
* node_lock must be hold
*/
static void
mark_children_scanned(device_node_info *node)
{
device_node_info *child, *next_child;
TRACE(("mark_children_scanned()\n"));
for (child = node->children; child != NULL; child = next_child) {
uint8 never_rescan, no_live_rescan;
next_child = child->siblings_next;
// ignore dead children
if (!child->registered)
continue;
// check whether device can be rescanned at all
if (pnp_get_attr_uint8_nolock(child, PNP_DRIVER_NEVER_RESCAN,
&never_rescan, false) == B_OK && never_rescan) {
TRACE(("no rescan allowed on device %p\n", child));
continue;
}
if (pnp_get_attr_uint8_nolock(child, PNP_DRIVER_NO_LIVE_RESCAN,
&no_live_rescan, false) != B_OK)
no_live_rescan = false;
if (no_live_rescan) {
TRACE(("no life rescan allowed on device %p\n", child));
if (child->load_count + child->loading > 0) {
TRACE(("device %p loaded - skipping it\n", child));
continue;
}
child->blocked_by_rescan = true;
++child->load_block_count;
}
child->verifying = true;
child->redetected = false;
// unload driver during rescan if needed
// (need to lock next_child temporarily as we release node_lock)
if (next_child)
++next_child->ref_count;
benaphore_unlock(&gNodeLock);
pnp_unload_driver_automatically(child, true);
benaphore_lock(&gNodeLock);
if (next_child)
pnp_remove_node_ref_nolock(next_child);
}
}
/** stop children verification, resetting associated flag and unblocking loads. */
static void
reset_children_verification(device_node_info *node)
{
device_node_info *child, *next_child;
TRACE(("reset_children_verification()\n"));
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
for (child = node->children; child != NULL; child = next_child) { pnp_probe_waiting_children_nolock(node);
next_child = child->siblings_next;
if (!child->verifying)
continue;
child->verifying = false;
if (child->blocked_by_rescan) {
child->blocked_by_rescan = false;
pnp_unblock_load(child);
}
if (next_child)
++next_child->ref_count;
benaphore_unlock(&gNodeLock);
pnp_load_driver_automatically(node, true);
benaphore_lock(&gNodeLock);
if (next_child)
pnp_remove_node_ref_nolock(next_child);
}
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
} }
#endif
/** unregister child nodes that weren't detected anymore */
static void
unregister_lost_children(device_node_info *node)
{
device_node_info *child, *dependency_list;
TRACE(("unregister_lost_children()\n"));
benaphore_lock(&gNodeLock);
for (child = node->children, dependency_list = NULL; child != NULL;
child = child->siblings_next) {
if (child->verifying && !child->redetected) {
TRACE(("removing lost device %p\n", child));
// child wasn't detected anymore - put it onto remove list
pnp_unregister_node_rec(child, &dependency_list);
}
}
benaphore_unlock(&gNodeLock);
// finish verification of children
// (must be done now to unblock them;
// else we risk deadlocks during notification)
reset_children_verification(node);
// inform all drivers of unregistered nodes
pnp_notify_unregistration(dependency_list);
// now, we can safely decrease ref_count of unregistered nodes
pnp_unref_unregistered_nodes(dependency_list);
}
/** recursively scan children of node (using depth-scan).
* node_lock must be hold
*/
static status_t
recursive_scan(device_node_info *node, uint depth)
{
device_node_info *child, *next_child;
status_t res;
TRACE(("recursive_scan(node: %p, depth=%d)\n", node, depth));
child = node->children;
// the child we want to access must be locked
if (child != NULL)
++child->ref_count;
for (; child != NULL; child = next_child) {
next_child = child->siblings_next;
// lock next child, so its node is still valid after rescan
if (next_child != NULL)
++next_child->ref_count;
// during rescan, we must release node_lock to not deadlock
benaphore_unlock(&gNodeLock);
res = pnp_rescan(child, depth - 1);
benaphore_lock(&gNodeLock);
// unlock current child as it's not accessed anymore
pnp_remove_node_ref_nolock(child);
// ignore errors because of touching unregistered nodes
if (res != B_OK && res != B_NAME_NOT_FOUND)
goto err;
}
// no need unlock last child (don't be loop already)
TRACE(("recursive_scan(): done\n"));
return B_OK;
err:
if (next_child != NULL)
pnp_remove_node_ref_nolock(next_child);
TRACE(("recursive_scan(): failed\n"));
return res;
}
/** ask bus to (re-)scan for connected devices */ /** ask bus to (re-)scan for connected devices */
static void static void
rescan_bus(device_node_info *node) scan_bus(device_node_info *node, bool rescan)
{ {
// busses can register their children themselves // busses can register their children themselves
bus_module_info *interface; bus_module_info *interface;
void *cookie; void *cookie;
bool defer_probe;
uint8 defer_probe_var;
// delay children probing if requested
defer_probe = pnp_get_attr_uint8(node,
PNP_BUS_DEFER_PROBE, &defer_probe_var, false ) == B_OK
&& defer_probe_var != 0;
if (defer_probe) {
TRACE(("defer probing for consumers\n"));
pnp_defer_probing_of_children(node);
}
// load driver during rescan // load driver during rescan
pnp_load_driver(node, NULL, (driver_module_info **)&interface, &cookie); pnp_load_driver(node, NULL, (driver_module_info **)&interface, &cookie);
@@ -320,127 +106,131 @@ rescan_bus(device_node_info *node)
// concurrently has been assured to not happen) // concurrently has been assured to not happen)
pnp_start_hook_call(node); pnp_start_hook_call(node);
if (interface->rescan != NULL) if (rescan) {
interface->rescan(cookie); if (interface->rescan_bus != NULL)
interface->rescan_bus(cookie);
} else {
if (interface->register_child_devices != NULL)
interface->register_child_devices(cookie);
}
pnp_finish_hook_call(node); pnp_finish_hook_call(node);
pnp_unload_driver(node); pnp_unload_driver(node);
// time to execute delayed probing // time to execute delayed probing
if (defer_probe) // pnp_probe_waiting_children(node);
pnp_probe_waiting_children(node);
} }
/** rescan for consumers /** recursively scan children of node (using depth-scan).
* ignore_fixed_consumers - true, to leave fixed consumers alone * node_lock must be hold
*/ */
status_t static status_t
pnp_rescan_int(device_node_info *node, uint32 depth, recursive_scan(device_node_info *node)
bool ignore_fixed_consumers)
{ {
bool is_bus; device_node_info *child = NULL;
status_t status;
TRACE(("recursive_scan(node = %p)\n", node));
while ((child = list_get_next_item(&node->children, child)) != NULL) {
dm_get_node_nolock(child);
// during rescan, we must release node_lock to not deadlock
benaphore_unlock(&gNodeLock);
status = scan(child, true);
benaphore_lock(&gNodeLock);
// unlock current child as it's not accessed anymore
dm_put_node_nolock(child);
// ignore errors because of touching unregistered nodes
if (status != B_OK && status != B_NAME_NOT_FOUND)
return status;
}
// no need unlock last child (don't be loop already)
TRACE(("recursive_scan(): done\n"));
return B_OK;
}
/** (re)scan for child nodes
*/
static status_t
scan(device_node_info *node, bool rescan)
{
status_t status = B_OK;
uint8 dummy; uint8 dummy;
status_t res = B_OK; bool isBus;
TRACE(("pnp_rescan_int(node: %p, depth = %ld)\n", node, depth)); TRACE(("scan(node = %p, mode: %s)\n", node, rescan ? "rescan" : "register"));
//pnp_load_boot_links(); isBus = pnp_get_attr_uint8(node, PNP_BUS_IS_BUS, &dummy, false) == B_OK;
// ignore depth 0 silently
if (depth == 0) {
res = B_OK;
goto err3;
}
is_bus = pnp_get_attr_uint8(node, PNP_BUS_IS_BUS, &dummy, false) == B_OK;
benaphore_lock(&gNodeLock);
// don't scan unregistered nodes
if (!node->registered) {
TRACE(("node not registered"));
res = B_NAME_NOT_FOUND;
goto err2;
}
if (!is_rescan_sensible(node)) {
// somebody else does the rescan, so no need to report error
TRACE(("rescan not sensible\n"));
res = B_OK;
goto err2;
}
// mark old devices
// exception: during registration, fixed consumers are
// initialized seperately, and we don't want to mark their node
// as being old
if (!ignore_fixed_consumers || is_bus)
mark_children_scanned(node);
// tell other scans what we are doing to avoid double scans
node->rescan_depth = depth;
// keep node alive
++node->ref_count;
benaphore_unlock(&gNodeLock);
// do the real thing - scan node // do the real thing - scan node
if (is_bus) if (!rescan) {
rescan_bus(node); bool loadDriversLater = false;
char *deviceType = NULL;
pnp_get_attr_uint8(node, B_DRIVER_FIND_DEVICES_ON_DEMAND, &loadDriversLater, false);
pnp_get_attr_string(node, B_DRIVER_DEVICE_TYPE, &deviceType, false);
// ask possible consumers to register their nodes if (isBus)
if (!ignore_fixed_consumers) { scan_bus(node, false);
TRACE(("scan fixed consumers\n"));
res = pnp_notify_fixed_consumers(node); // ask possible children to register their nodes
if (res != B_OK)
goto err; if (!loadDriversLater && deviceType == NULL) {
status = dm_register_dynamic_child_devices(node);
if (status != B_OK)
return status;
}
free(deviceType);
} }
res = pnp_notify_dynamic_consumers(node);
if (res != B_OK)
goto err;
// unregister children that weren't detected anymore
unregister_lost_children(node);
benaphore_lock(&gNodeLock); benaphore_lock(&gNodeLock);
// mark scan as being finished to not block recursive scans
node->rescan_depth = 0;
// scan children recursively; // scan children recursively;
// keep the node_lock to make sure noone removes children meanwhile // keep the node_lock to make sure noone removes children meanwhile
if (depth > 1) if (rescan && isBus)
res = recursive_scan(node, depth); status = recursive_scan(node);
pnp_remove_node_ref_nolock(node);
benaphore_unlock(&gNodeLock); benaphore_unlock(&gNodeLock);
//pnp_unload_boot_links(); TRACE(("scan(): done (%p) - %s\n", node, strerror(status)));
return status;
TRACE(("pnp_rescan_int(): done (%p) - %s\n", node, strerror(res)));
return res;
err:
reset_children_verification(node);
benaphore_lock(&gNodeLock);
node->rescan_depth = 0;
pnp_remove_node_ref_nolock(node);
err2:
benaphore_unlock(&gNodeLock);
TRACE(("pnp_rescan_int(): failed (%p, %s)\n", node, strerror(res)));
err3:
//pnp_unload_boot_links();
return res;
} }
// #pragma mark -
/** Rescan device node (only works if it's a bus) */
status_t
dm_rescan(device_node_info *node)
{
// only allow a single rescan at a time
if (atomic_add(&sRescanning, 1) > 0) {
atomic_add(&sRescanning, -1);
return B_BUSY;
}
return scan(node, true);
}
/** execute registration of fully constructed node */
status_t
dm_register_child_devices(device_node_info *node)
{
return scan(node, false);
}
+51 -50
View File
@@ -266,37 +266,44 @@ devfs_find_in_dir(struct devfs_vnode *dir, const char *path)
static status_t static status_t
devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *v) devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *vnode)
{ {
if (!S_ISDIR(dir->stream.type)) if (!S_ISDIR(dir->stream.type))
return B_BAD_VALUE; return B_BAD_VALUE;
v->dir_next = dir->stream.u.dir.dir_head; vnode->dir_next = dir->stream.u.dir.dir_head;
dir->stream.u.dir.dir_head = v; dir->stream.u.dir.dir_head = vnode;
v->parent = dir; vnode->parent = dir;
dir->modification_time = time(NULL); dir->modification_time = time(NULL);
notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name, vnode->id);
notify_stat_changed(sDeviceFileSystem->id, dir->id, B_STAT_MODIFICATION_TIME);
return B_OK; return B_OK;
} }
static status_t static status_t
devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *findit) devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *removeNode)
{ {
struct devfs_vnode *v; struct devfs_vnode *vnode = dir->stream.u.dir.dir_head;
struct devfs_vnode *last_v; struct devfs_vnode *lastNode = NULL;
for (v = dir->stream.u.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) { for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) {
if (v == findit) { if (vnode == removeNode) {
/* make sure all dircookies dont point to this vnode */ // make sure no dircookies point to this vnode
update_dircookies(dir, v); update_dircookies(dir, vnode);
if (last_v) if (lastNode)
last_v->dir_next = v->dir_next; lastNode->dir_next = vnode->dir_next;
else else
dir->stream.u.dir.dir_head = v->dir_next; dir->stream.u.dir.dir_head = vnode->dir_next;
v->dir_next = NULL; vnode->dir_next = NULL;
dir->modification_time = time(NULL); dir->modification_time = time(NULL);
notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name, vnode->id);
notify_stat_changed(sDeviceFileSystem->id, dir->id, B_STAT_MODIFICATION_TIME);
return B_OK; return B_OK;
} }
} }
@@ -927,7 +934,7 @@ devfs_get_vnode(fs_volume _fs, vnode_id id, fs_vnode *_vnode, bool reenter)
TRACE(("devfs_get_vnode: looked it up at %p\n", *_vnode)); TRACE(("devfs_get_vnode: looked it up at %p\n", *_vnode));
if (*_vnode) if (*_vnode)
return 0; return B_OK;
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
@@ -1535,7 +1542,7 @@ devfs_write_stat(fs_volume _fs, fs_vnode _vnode, const struct stat *stat, uint32
mutex_unlock(&fs->lock); mutex_unlock(&fs->lock);
notify_listener(B_STAT_CHANGED, fs->id, 0, 0, vnode->id, NULL); notify_stat_changed(fs->id, vnode->id, statMask);
return B_OK; return B_OK;
} }
@@ -1626,15 +1633,11 @@ file_system_info gDeviceFileSystem = {
// temporary hack to get it to work with the current device manager // temporary hack to get it to work with the current device manager
static device_manager_info *pnp; static device_manager_info *sDeviceManager;
static const device_attr pnp_devfs_attrs[] = static const device_attr pnp_devfs_attrs[] = {
{ { B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: "devfs_device_notifier" }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "devfs" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "devfs" }},
{ NULL } { NULL }
}; };
@@ -1644,20 +1647,13 @@ static const device_attr pnp_devfs_attrs[] =
static status_t static status_t
pnp_devfs_register_device(device_node_handle parent) pnp_devfs_register_device(device_node_handle parent)
{ {
char *str = NULL, *filename = NULL; char *filename = NULL;
device_node_handle node; device_node_handle node;
status_t status; status_t status;
TRACE(("pnp_devfs_probe()\n")); TRACE(("pnp_devfs_probe()\n"));
// make sure we can handle this parent if (sDeviceManager->get_attr_string(parent, PNP_DEVFS_FILENAME, &filename, true) != B_OK) {
if (pnp->get_attr_string(parent, PNP_DRIVER_TYPE, &str, false) != B_OK
|| strcmp(str, PNP_DEVFS_TYPE_NAME) != 0) {
status = B_ERROR;
goto err1;
}
if (pnp->get_attr_string(parent, PNP_DEVFS_FILENAME, &filename, true) != B_OK) {
dprintf("devfs: Item containing file name is missing\n"); dprintf("devfs: Item containing file name is missing\n");
status = B_ERROR; status = B_ERROR;
goto err1; goto err1;
@@ -1665,13 +1661,16 @@ pnp_devfs_register_device(device_node_handle parent)
TRACE(("Adding %s\n", filename)); TRACE(("Adding %s\n", filename));
pnp_devfs_driver_info *info; status = sDeviceManager->register_device(parent, pnp_devfs_attrs, NULL, &node);
status = pnp->load_driver(parent, NULL, (driver_module_info **)&info, NULL); if (status != B_OK || node == NULL)
if (status != B_OK)
goto err1; goto err1;
status = pnp->register_device(parent, pnp_devfs_attrs, NULL, &node); // ToDo: this is a hack to get things working (init_driver() only works for registered nodes)
if (status != B_OK || node == NULL) parent->registered = true;
pnp_devfs_driver_info *info;
status = sDeviceManager->init_driver(parent, NULL, (driver_module_info **)&info, NULL);
if (status != B_OK)
goto err2; goto err2;
//add_device(device); //add_device(device);
@@ -1683,11 +1682,10 @@ pnp_devfs_register_device(device_node_handle parent)
return B_OK; return B_OK;
err3: err3:
pnp->unregister_device(node); sDeviceManager->uninit_driver(parent);
err2: err2:
pnp->unload_driver(parent); sDeviceManager->unregister_device(node);
err1: err1:
free(str);
free(filename); free(filename);
return status; return status;
@@ -1728,9 +1726,9 @@ pnp_devfs_device_removed(device_node_handle node, void *cookie)
#endif #endif
TRACE(("pnp_devfs_device_removed()\n")); TRACE(("pnp_devfs_device_removed()\n"));
#if 0 #if 0
parent = pnp->get_parent(node); parent = sDeviceManager->get_parent(node);
// don't use cookie - we don't use pnp loading scheme but // don't use cookie - we don't use sDeviceManager loading scheme but
// global data and keep care of everything ourself! // global data and keep care of everything ourself!
ACQUIRE_BEN( &device_list_lock ); ACQUIRE_BEN( &device_list_lock );
@@ -1738,9 +1736,9 @@ pnp_devfs_device_removed(device_node_handle node, void *cookie)
if( device->parent == parent ) if( device->parent == parent )
break; break;
} }
if( device != NULL ) { if( device != NULL ) {
pnp_devfs_remove_device( device ); pnp_devfs_remove_device(device);
} else { } else {
SHOW_ERROR( 0, "bug: node %p couldn't been found", node ); SHOW_ERROR( 0, "bug: node %p couldn't been found", node );
res = B_NAME_NOT_FOUND; res = B_NAME_NOT_FOUND;
@@ -1758,10 +1756,10 @@ pnp_devfs_std_ops(int32 op, ...)
{ {
switch (op) { switch (op) {
case B_MODULE_INIT: case B_MODULE_INIT:
return get_module(DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp); return get_module(B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager);
case B_MODULE_UNINIT: case B_MODULE_UNINIT:
put_module(DEVICE_MANAGER_MODULE_NAME); put_module(B_DEVICE_MANAGER_MODULE_NAME);
return B_OK; return B_OK;
default: default:
@@ -1777,10 +1775,13 @@ driver_module_info gDeviceForDriversModule = {
pnp_devfs_std_ops pnp_devfs_std_ops
}, },
NULL, NULL, // supports device
NULL,
pnp_devfs_register_device, pnp_devfs_register_device,
pnp_devfs_device_removed NULL, // init driver
NULL, // uninit driver
pnp_devfs_device_removed,
NULL, // cleanup
NULL, // get paths
}; };