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.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
PCI bus manager
@@ -11,10 +11,9 @@
#define _PCI2_H
#include <device_manager.h>
//#include "r5_wrapper.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
typedef struct pci_info {
@@ -89,26 +88,22 @@ typedef struct pci_device_info *pci_device;
typedef struct pci_device_module_info {
driver_module_info info;
uint8 (*read_io_8) (pci_device device, int mapped_io_addr);
void (*write_io_8) (pci_device device, int mapped_io_addr, uint8 value);
uint16 (*read_io_16) (pci_device device, int mapped_io_addr);
void (*write_io_16) (pci_device device, int mapped_io_addr, uint16 value);
uint32 (*read_io_32) (pci_device device, int mapped_io_addr);
void (*write_io_32) (pci_device device, int mapped_io_addr, uint32 value);
uint8 (*read_io_8)(pci_device device, int mapped_io_addr);
void (*write_io_8)(pci_device device, int mapped_io_addr, uint8 value);
uint16 (*read_io_16)(pci_device device, int mapped_io_addr);
void (*write_io_16)(pci_device device, int mapped_io_addr, uint16 value);
uint32 (*read_io_32)(pci_device device, int mapped_io_addr);
void (*write_io_32)(pci_device device, int mapped_io_addr, uint32 value);
uint32 (*read_pci_config) (
pci_device device,
uint32 (*read_pci_config)(pci_device device,
uchar offset, /* offset in configuration space */
uchar size /* # bytes to read (1, 2 or 4) */
);
void (*write_pci_config) (
pci_device device,
uchar size); /* # bytes to read (1, 2 or 4) */
void (*write_pci_config)(pci_device device,
uchar offset, /* offset in configuration space */
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 (*release_iomem)( void *base, size_t len );
@@ -118,8 +113,6 @@ typedef struct pci_device_module_info {
} pci_device_module_info;
// type of PCI device
#define PCI_DEVICE_TYPE_NAME "pci/device/v1"
// directory of PCI drivers
#define PCI_DRIVERS_DIR "pci"
+60 -413
View File
@@ -2,136 +2,10 @@
* Copyright 2004-2005, Haiku Inc. All Rights Reserved.
* 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
#define _DEVICE_MANAGER_H
#include <TypeConstants.h>
#include <Drivers.h>
#include <module.h>
@@ -155,7 +29,7 @@ typedef struct {
// I/O port: first port address (16 bit)
// ISA DMA channel: channel number (0-7)
uint32 len;
uint32 length;
// I/O memory: size of address range (32 bit)
// I/O port: size of port range (16 bit)
// ISA DMA channel: must be 1
@@ -173,98 +47,48 @@ typedef struct {
const char *string; // B_STRING_TYPE
struct { // B_RAW_TYPE
void *data;
size_t len;
size_t length;
} raw;
} value;
} device_attr;
// handle of device node
typedef struct device_node_info *device_node_handle;
// handle of acquired I/O resource
typedef struct io_resource_info *io_resource_handle;
// handle of node attribute
typedef struct device_attr_info *device_attr_handle;
typedef struct driver_module_info driver_module_info;
// interface of PnP manager
// interface of the device manager
typedef struct device_manager_info {
module_info info;
// load driver
// 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,
status_t (*init_driver)(device_node_handle node, void *userCookie,
driver_module_info **interface, void **cookie);
// unload driver
status_t (*unload_driver)(device_node_handle node);
status_t (*uninit_driver)(device_node_handle node);
// rescan node for new dynamic drivers
// node - node whose dynamic drivers are to be scanned
// depth - recursive depth (>= 1)
status_t (*rescan)(device_node_handle node, uint32 depth);
status_t (*rescan)(device_node_handle node);
// 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,
const device_attr *attrs,
const io_resource_handle *io_resources,
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);
// acquire I/O resources
// resources - NULL-terminated array of resources to acquire
// handles - NULL-terminated array of handles (one per resource);
// array must be provided by caller
// return B_BUSY if a resource is used by a loaded driver
status_t (*get_next_child_device)(device_node_handle parent,
device_node_handle *_node, const device_attr *attrs);
device_node_handle (*get_parent)(device_node_handle node);
void (*put_device_node)(device_node_handle node);
status_t (*acquire_io_resources)(io_resource *resources,
io_resource_handle *handles);
// release I/O resources
// handles - NULL-terminated array of 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);
// free unique 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,
const char *name, uint8 *value, bool recursive);
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,
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,
device_attr_handle *attrHandle);
// release attribute handle <attr_handle> of <node>;
// see get_next_attr
status_t (*release_attr)(device_node_handle node,
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,
const device_attr **attr);
// change/add attribute <attr> of/to node
status_t (*write_attr)(device_node_handle node,
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);
} device_manager_info;
// standard attributes:
// 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.
*/
#define B_DEVICE_MANAGER_MODULE_NAME "system/device_manager/v1"
// interface of device driver
struct driver_module_info {
module_info info;
status_t (*init_device)(device_node_handle node, void *user_cookie, void **cookie);
// 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.
float (*supports_device)(device_node_handle parent, bool *_noConnection);
status_t (*register_device)(device_node_handle parent);
// parent was added or is rescanned.
// check whether this parent is supported and register
// any consumer device. Dynamic consumers must return
// B_OK if they support this parent. All other return
// values are ignored.
status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie);
status_t (*uninit_driver)(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);
// 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_DRIVER_DRIVER "driver"
// type of driver (required, string)
#define PNP_DRIVER_TYPE "type"
// module name of fixed consumer - see pnp_manager.h (optional, string)
// append "/0", "/1" etc. if there are multiple fixed consumers
#define PNP_DRIVER_FIXED_CONSUMER "consumer/fixed"
// dynamic consumers pattern - see pnp_manager.h (optional, string)
// append "/0", "/1" etc. if there are multiple dynamic consumers
#define PNP_DRIVER_DYNAMIC_CONSUMER "consumer/dynamic"
#define PNP_MANAGER_ID_GENERATOR "id_generator"
// 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_AUTO_ID "auto_id"
// generated id (uint32)
#define B_DRIVER_MODULE "driver/module"
#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"
// pattern device identifier (optional, string)
// it is expanded and used to detect changed devices
#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"
// connection of parent the device is attached to (optional, string)
// there can be only one device per connection
// former pnp_bus.h
/*
Copyright (c) 2003-04, Thomas Kurschel
// interface of a bus device driver
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 {
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
// be called concurrently
status_t (*rescan) (void *cookie);
status_t (*rescan_bus)(void *cookie);
} bus_module_info;
// standard attributes:
// standard attributes
// PnP bus identification (required, uint8)
// define this to let the PnP manager know that this is a PnP bus
// the actual content is ignored
#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 */
+6 -8
View File
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
PnP devfs driver interface.
@@ -20,9 +20,10 @@
#ifndef _PNP_DEVFS_H
#define _PNP_DEVFS_H
#include <Drivers.h>
#include <device_manager.h>
//#include "r5_wrapper.h"
// changed open hook - gets cookie returned by init_device instead of name
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)
#define PNP_DEVFS_FILENAME "devfs/filename"
// type of devfs device drivers
#define PNP_DEVFS_TYPE_NAME "devfs_device"
#define PNP_DEVFS_MODULE_NAME "sys/pnp_devfs/v1"
#define PNP_DEVFS_MODULE_NAME "system/devfs/device_v1"
#endif
+7 -12
View File
@@ -9,25 +9,23 @@
#include <SupportDefs.h>
#include <device_manager.h>
#include <util/list.h>
typedef struct device_node_info device_node_info;
// info about a device node
struct device_node_info {
device_node_info *prev, *next;
device_node_info *siblings_prev, *siblings_next;
device_node_info *notify_prev, *notify_next;
struct list_link siblings;
device_node_info *parent;
device_node_info *children;
int32 ref_count; // reference count; see registration.c
struct list children;
int32 ref_count;
driver_module_info *driver;
void *cookie;
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 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
sem_id hook_sem; // sem for waiting hook calls
int32 load_block_count; // load-block nest count
@@ -39,10 +37,7 @@ struct device_node_info {
struct device_attr_info *attributes; // list of attributes
uint32 num_io_resources; // number of I/O resources
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
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
ide_channel_added(device_node_handle parent)
{
char *str = NULL, *controller_name = NULL;
char *controller_name = NULL;
uint32 channel_id;
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,
&controller_name, true) != B_OK) {
pnp->get_attr_string(parent, PNP_DRIVER_DRIVER, &str, false);
SHOW_ERROR( 0, "Ignored controller managed by %s - controller name missing", str);
dprintf("ide: ignored controller - controller name missing\n");
goto err;
}
@@ -52,9 +47,9 @@ ide_channel_added(device_node_handle parent)
{
device_attr attrs[] =
{
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_SIM_TYPE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ string: controller_name }},
// 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);
free(str);
free(controller_name);
return res;
}
err:
free(str);
free(controller_name);
return B_NO_MEMORY;
@@ -117,9 +110,10 @@ ide_for_controller_interface ide_for_controller_module = {
&std_ops
},
NULL,
NULL,
NULL, // supported devices
ide_channel_added,
NULL,
NULL,
NULL
},
+33 -22
View File
@@ -34,6 +34,7 @@ scsi_for_sim_interface *scsi;
fast_log_info *fast_log;
#ifdef USE_FAST_LOG
static fast_log_event_type ide_events[] =
{
{ 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" },
{}
};
#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 */
@@ -541,6 +544,7 @@ finish_all_requests(ide_device_info *device, ide_qrequest *ignore,
static status_t
ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
{
device_node_handle parent;
ide_bus_info *bus;
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);
}
#if 0
bus->log = fast_log->start_log(bus->name, ide_events);
if (bus->log == NULL) {
res = B_NO_MEMORY;
goto err;
}
#endif
init_synced_pc(&bus->scan_bus_syncinfo, scan_device_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;
}
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,
(void **)&bus->channel);
pnp->put_device_node(parent);
if (res != B_OK)
goto err5;
@@ -654,16 +664,15 @@ err4:
delete_sem(bus->scan_device_sem);
err3:
delete_sem(bus->sync_wait_sem);
err2:
scsi->free_dpc(bus->irq_dpc);
err1:
uninit_synced_pc(&bus->scan_bus_syncinfo);
uninit_synced_pc(&bus->disconnect_syncinfo);
#ifdef USE_FAST_LOG
fast_log->stop_log(bus->log);
err:
#endif
free(bus);
return res;
@@ -673,7 +682,10 @@ err:
static status_t
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_sem(bus->scan_device_sem);
@@ -681,7 +693,7 @@ ide_sim_uninit_bus(ide_bus_info *bus)
scsi->free_dpc(bus->irq_dpc);
uninit_synced_pc(&bus->scan_bus_syncinfo);
uninit_synced_pc(&bus->disconnect_syncinfo);
fast_log->stop_log(bus->log);
// fast_log->stop_log(bus->log);
free(bus);
@@ -769,9 +781,8 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = {
{ FAST_LOG_MODULE_NAME, (module_info **)&fast_log },
{ 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,
std_ops,
},
NULL, // supported devices
NULL, // register node
(status_t (*)(device_node_handle, void *, void **))ide_sim_init_bus,
(status_t (*)( void *)) ide_sim_uninit_bus,
NULL,
(status_t (*)(void *) ) ide_sim_uninit_bus,
(void (*)(device_node_handle, void *)) ide_sim_bus_removed
},
(void (*)( scsi_sim_cookie, scsi_ccb * )) sim_scsi_io,
(uchar (*)( scsi_sim_cookie, scsi_ccb * )) sim_abort,
(uchar (*)( scsi_sim_cookie, uchar, uchar )) sim_reset_device,
(uchar (*)( scsi_sim_cookie, scsi_ccb * )) sim_term_io,
(void (*)(scsi_sim_cookie, scsi_ccb *)) sim_scsi_io,
(uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_abort,
(uchar (*)(scsi_sim_cookie, uchar, uchar)) sim_reset_device,
(uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_term_io,
(uchar (*)( scsi_sim_cookie, scsi_path_inquiry * )) sim_path_inquiry,
(uchar (*)( scsi_sim_cookie )) sim_scan_bus,
(uchar (*)( scsi_sim_cookie )) sim_reset_bus,
(uchar (*)(scsi_sim_cookie, scsi_path_inquiry *))sim_path_inquiry,
(uchar (*)(scsi_sim_cookie)) sim_scan_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
};
+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.
*
* Distributed under the terms of the MIT License.
*/
@@ -31,7 +33,7 @@
// (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;
@@ -96,6 +98,7 @@ static long
make_isa_dma_table(const void *buffer, long buffer_size, ulong num_bits,
isa_dma_entry *table, long num_entries)
{
// ToDo: implement this?!
return ENOSYS;
}
@@ -104,8 +107,7 @@ static status_t
start_isa_dma(long channel, void *buf, long transfer_count,
uchar mode, uchar e_mode)
{
// TBD
// ToDo
// ToDo: implement this?!
return B_NOT_ALLOWED;
}
@@ -114,6 +116,7 @@ static long
start_scattered_isa_dma(long channel, const isa_dma_entry *table,
uchar mode, uchar emode)
{
// ToDo: implement this?!
return ENOSYS;
}
@@ -121,8 +124,7 @@ start_scattered_isa_dma(long channel, const isa_dma_entry *table,
static status_t
lock_isa_dma_channel(long channel)
{
// TBD
// ToDo
// ToDo: implement this?!
return B_NOT_ALLOWED;
}
@@ -130,14 +132,13 @@ lock_isa_dma_channel(long channel)
static status_t
unlock_isa_dma_channel(long channel)
{
// TBD
// ToDo
// ToDo: implement this?!
return B_ERROR;
}
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;
return B_OK;
@@ -145,52 +146,61 @@ isa_init_device(device_node_handle node, void *user_cookie, void **cookie)
static status_t
isa_uninit_device(void *cookie)
isa_uninit_driver(void *cookie)
{
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
isa_device_added(device_node_handle parent)
isa_register_device(device_node_handle parent)
{
static const device_attr attrs[] = {
// info about ourself
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: ISA_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: ISA_DEVICE_TYPE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: ISA_MODULE_NAME }},
// unique connection
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }},
// mark as being a bus
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
// tell where to look for consumers
// ToDo: temporary hack to get things started!
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "busses/ide/ide_isa/isa/device/v1" }},
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string: ISA_DRIVERS_DIR "/" }},
// tell where to look for child devices
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "isa" }},
{ B_DRIVER_FIND_DEVICES_ON_DEMAND, B_UINT8_TYPE, { ui8: 1 }},
{ B_DRIVER_EXPLORE_LAST, B_UINT8_TYPE, { ui8: 1 }},
{ NULL }
};
device_node_handle node;
char *parent_type;
status_t res;
return pnp->register_device(parent, attrs, NULL, NULL);
}
// 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")) {
free(parent_type);
return B_ERROR;
}
free(parent_type);
static void
isa_get_paths(const char ***_bus, const char ***_device)
{
static const char *kBus[] = {"root", NULL};
res = pnp->register_device(parent, attrs, NULL, &node);
if (res != B_OK)
return res;
return B_OK;
*_bus = kBus;
*_device = NULL;
}
@@ -209,7 +219,7 @@ std_ops(int32 op, ...)
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
},
isa_init_device,
isa_uninit_device,
isa_device_added,
NULL
isa_supports_device,
isa_register_device,
isa_init_driver,
isa_uninit_driver,
NULL, // removed device
NULL, // cleanup device
isa_get_paths,
},
// this rescan(); as ISA relies on device drivers to detect their
// devices themselves, we don't have an universal rescan method
NULL
// as ISA relies on device drivers to detect their devices themselves,
// we don't have an universal rescan method
NULL, // register child devices
NULL, // rescan bus
},
isa_read_io_8, isa_write_io_8,
@@ -265,12 +279,8 @@ static isa2_module_info isa2_module = {
start_isa_dma,
};
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = {
(module_info *)&isa_module,
(module_info *)&isa2_module,
NULL
};
#endif
@@ -7,6 +7,7 @@ KernelAddon pci : kernel bus_managers :
pci.cpp
pci_info.cpp
pci_module.c
pci_device.c
kernel_cpp.cpp
: 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 <PCI.h>
#include "util/kernel_cpp.h"
#include "pci_priv.h"
#include "pci.h"
static PCI *pcidb;
void
bool gIrqRouterAvailable = false;
spinlock gConfigLock = 0;
static PCI *sPCI;
status_t
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
pci_uninit(void)
{
delete pcidb;
delete sPCI;
}
long
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
#ifndef TRACE_PCI
#define TRACE(x)
# define TRACE(x) ;
#else
#define TRACE(x) dprintf x
# define TRACE(x) dprintf x
#endif
void pci_init(void);
void pci_uninit(void);
long pci_get_nth_pci_info(long index, pci_info *outInfo);
#ifdef __cplusplus
struct PCIBus;
struct PCIDev;
struct PCIBus
{
struct PCIBus {
PCIDev *parent;
uint8 bus;
PCIDev *child;
};
struct PCIDev
{
struct PCIDev {
PCIDev *next;
PCIBus *parent;
PCIBus *child;
@@ -37,37 +40,48 @@ struct PCIDev
pci_info info;
};
class PCI
{
public:
PCI();
~PCI();
class PCI {
public:
PCI();
~PCI();
status_t GetNthPciInfo(long index, pci_info *outInfo);
status_t GetNthPciInfo(long index, pci_info *outInfo);
private:
void DiscoverBus(PCIBus *bus);
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);
private:
void DiscoverBus(PCIBus *bus);
void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func);
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;
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);
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
#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
}
#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 <device_manager.h>
#include <bus_manager.h>
#include <PCI.h>
#include <string.h>
#include <stdlib.h>
#include "pci_priv.h"
#include "pci_info.h"
#include "pci.h"
bool gIrqRouterAvailable = false;
spinlock gConfigLock = 0;
status_t pci_module_init(void);
status_t pci_module_uninit(void);
int32 pci_module_std_ops(int32 op, ...);
status_t pci_module_rescan(void);
device_manager_info *gDeviceManager;
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()) {
TRACE(("PCI: pci_io_init failed\n"));
// make sure parent is really device root
if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
return B_ERROR;
if (strcmp(bus, "root")) {
free(bus);
return 0.0;
}
if (B_OK != pci_config_init()) {
TRACE(("PCI: pci_config_init failed\n"));
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;
free(bus);
return 1.0;
}
status_t
pci_module_uninit(void)
static status_t
pci_module_register_device(device_node_handle parent)
{
TRACE(("PCI: pci_module_uninit\n"));
pci_uninit();
return B_OK;
io_resource resources[2] = {
{ IO_PORT, PCI_CONFIG_ADDRESS, 8 },
{}
};
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
pci_module_rescan(void)
static status_t
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;
}
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, ...)
{
switch (op) {
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:
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_KEEP_LOADED,
pci_module_std_ops
pci_old_module_std_ops
},
pci_module_rescan
NULL
},
&pci_read_io_8,
&pci_write_io_8,
@@ -93,8 +233,40 @@ struct pci_module_info pci_module = {
&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 *)&pci_module,
(module_info *)&sOldPCIModule,
(module_info *)&sPCIModule,
(module_info *)&gPCIDeviceModule,
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 <device_manager.h>
#include <bus/PCI.h>
#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);
// name of PCI device modules
#define PCI_DEVICE_MODULE_NAME "bus_managers/pci/device_v1"
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);
// I/O port for PCI config space address
#define PCI_CONFIG_ADDRESS 0xcf8
// I/O port for PCI config space data
#define PCI_CONFIG_DATA 0xcfc
extern device_manager_info *gDeviceManager;
// 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 int gMaxBusDevices;
@@ -37,6 +58,30 @@ extern bool gIrqRouterAvailable;
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
}
#endif
#endif /* __PCI_PRIV_H__ */
+19 -14
View File
@@ -1,7 +1,7 @@
/*
** Copyright 2002-04, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI bus manager
@@ -35,12 +35,16 @@ static status_t
scsi_bus_raw_init_device(device_node_handle node,
void *userCookie, void **cookie)
{
device_node_handle parent = pnp->get_parent(node);
bus_raw_info *bus;
scsi_bus_interface *interface;
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);
pnp->put_device_node(parent);
if (res != B_OK)
return res;
@@ -57,11 +61,13 @@ scsi_bus_raw_init_device(device_node_handle node,
static status_t
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));
if (res != B_OK)
return res;
pnp->put_device_node(parent);
if (status != B_OK)
return status;
free(bus);
return B_OK;
@@ -86,13 +92,11 @@ scsi_bus_raw_probe(device_node_handle parent)
{
device_attr attributes[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ 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 }},
{}
};
@@ -185,9 +189,10 @@ pnp_devfs_driver_info scsi_bus_raw_module = {
std_ops
},
NULL,
scsi_bus_raw_probe,
scsi_bus_raw_init_device,
(status_t (*) (void *))scsi_bus_raw_uninit_device,
scsi_bus_raw_probe,
NULL,
NULL
},
+19 -8
View File
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI bus manager
@@ -182,6 +182,7 @@ scsi_destroy_bus(scsi_bus_info *bus)
static status_t
scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
{
device_node_handle parent;
uint8 path_id;
scsi_bus_info *bus;
status_t res;
@@ -239,8 +240,13 @@ scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
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);
pnp->put_device_node(parent);
if (res != B_OK)
goto err;
@@ -264,7 +270,10 @@ err:
static status_t
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);
return B_OK;
@@ -331,13 +340,15 @@ scsi_bus_interface scsi_bus_module = {
std_ops
},
NULL, // supported devices
NULL, // register node
scsi_init_bus,
(status_t (*) (void *)) scsi_uninit_bus,
NULL,
(status_t (*)(void *))scsi_uninit_bus,
NULL
},
(status_t (*) (void *)) scsi_scan_bus
(status_t (*)(void *))scsi_scan_bus,
NULL
},
scsi_inquiry_path,
+125 -113
View File
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI bus manager
@@ -22,6 +22,7 @@
#include <stdio.h>
#ifdef USE_FAST_LOG
static fast_log_event_type scsi_device_events[] = {
{ ev_scsi_requeue_request, "ev_scsi_requeue_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" },
{}
};
#endif
// free autosense request of device
static void scsi_free_autosense_request( scsi_device_info *device )
/** free autosense request of device */
static void
scsi_free_autosense_request(scsi_device_info *device)
{
SHOW_FLOW0( 3, "" );
if( device->auto_sense_request != NULL ) {
scsi_free_ccb( device->auto_sense_request );
if (device->auto_sense_request != NULL) {
scsi_free_ccb(device->auto_sense_request);
device->auto_sense_request = NULL;
}
if( device->auto_sense_area > 0 ) {
delete_area( device->auto_sense_area );
if (device->auto_sense_area > 0) {
delete_area(device->auto_sense_area);
device->auto_sense_area = 0;
}
}
// free all data of device
static void scsi_free_device( scsi_device_info *device )
/** free all data of device */
static void
scsi_free_device(scsi_device_info *device)
{
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 );
DELETE_BEN( &device->dma_buffer_lock );
delete_sem( device->dma_buffer_owner );
if( device->log != NULL )
fast_log->stop_log( device->log );
free( device );
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);
DELETE_BEN(&device->dma_buffer_lock);
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
// size of dst is dst_size, size of src is dst_size-1
static void beautify_string( char *dst, char *src, int dst_size )
/** copy string src without trailing zero to dst and remove trailing
* 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)
{
int i;
memcpy( dst, src, dst_size - 1 );
for( i = dst_size - 2; i >= 0; --i ) {
if( dst[i] != ' ' )
memcpy(dst, src, dst_size - 1);
for (i = dst_size - 2; i >= 0; --i) {
if (dst[i] != ' ')
break;
}
dst[i + 1] = 0;
}
}
/** 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];
device_attr attrs[] = {
// info about driver
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_DEVICE_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_DEVICE_TYPE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DEVICE_MODULE_NAME }},
// connection
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string:
"target: %"SCSI_DEVICE_TARGET_ID_ITEM
"%, lun: %"SCSI_DEVICE_TARGET_LUN_ITEM"%" }},
// inquiry data (used for both identification and information)
{ SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE,
{ 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
{ SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }},
{ SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }},
{ SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }},
{ SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }},
// description of peripheral drivers
// ToDo: temporary hack to get things started!
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "drivers/disk/scsi/scsi_dsk/scsi/device/v1" }},
{ 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 "%" }},
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "scsi" }},
// ToDo: mapping is missing
// extra restriction of maximum number of blocks per transfer
{ BLKDEV_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
// atapi emulation
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
// manual autosense
@@ -179,19 +181,19 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
// create data structure for a device
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)
{
scsi_device_info *device;
SHOW_FLOW0( 3, "" );
device = (scsi_device_info *)malloc( sizeof( *device ));
if( device == NULL )
device = (scsi_device_info *)malloc(sizeof(*device));
if (device == NULL)
return NULL;
memset( device, 0, sizeof( *device ));
memset(device, 0, sizeof(*device));
device->lock_count = device->blocked[0] = device->blocked[1] = 0;
device->sim_overflow = 0;
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->valid = true;
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;
device->dma_buffer_owner = create_sem( 1, "dma_buffer" );
if( device->dma_buffer_owner < 0 )
device->dma_buffer_owner = create_sem(1, "dma_buffer");
if (device->dma_buffer_owner < 0)
goto err2;
register_kernel_daemon( scsi_dma_buffer_daemon, device, 5 * 10 );
register_kernel_daemon(scsi_dma_buffer_daemon, device, 5 * 10);
return device;
err2:
DELETE_BEN( &device->dma_buffer_lock );
err:
free( device );
DELETE_BEN(&device->dma_buffer_lock);
err:
free(device);
return NULL;
}
// prepare autosense request.
// this cannot be done on demand but during init as we may
// have run out of ccbs when we need it
static status_t scsi_create_autosense_request( scsi_device_info *device )
/** prepare autosense request.
* this cannot be done on demand but during init as we may
* have run out of ccbs when we need it
*/
static status_t
scsi_create_autosense_request(scsi_device_info *device)
{
scsi_ccb *request;
char *buffer;
@@ -232,28 +238,28 @@ static status_t scsi_create_autosense_request( scsi_device_info *device )
size_t total_size;
SHOW_FLOW0( 3, "" );
device->auto_sense_request = request = scsi_alloc_ccb( device );
if( device->auto_sense_request == NULL )
device->auto_sense_request = request = scsi_alloc_ccb(device);
if (device->auto_sense_request == NULL)
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);
// allocate buffer for space sense data and S/G list
device->auto_sense_area = create_area( "auto_sense",
(void **)&buffer, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 0 );
if( device->auto_sense_area < 0 )
device->auto_sense_area = create_area("auto_sense",
(void **)&buffer, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 0);
if (device->auto_sense_area < 0)
goto err;
request->data = buffer;
request->data_len = SCSI_MAX_SENSE_SIZE;
request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE);
request->sg_cnt = 1;
get_memory_map( buffer, SCSI_MAX_SENSE_SIZE,
(physical_entry *)request->sg_list, 1 );
get_memory_map(buffer, SCSI_MAX_SENSE_SIZE,
(physical_entry *)request->sg_list, 1);
// disable auto-autosense, just in case;
// make sure no other request overtakes sense request;
// 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;
cmd = (scsi_cmd_request_sense *)request->cdb;
request->cdb_len = sizeof( *cmd );
memset( cmd, 0, sizeof( *cmd ));
request->cdb_len = sizeof(*cmd);
memset(cmd, 0, sizeof(*cmd));
cmd->opcode = SCSI_OP_REQUEST_SENSE;
cmd->LUN = device->target_lun;
cmd->alloc_length = SCSI_MAX_SENSE_SIZE;
return B_OK;
err:
scsi_free_ccb(request);
return B_NO_MEMORY;
@@ -282,6 +288,7 @@ err:
static status_t
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;
uint8 target_id, target_lun, path_id;
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
|| inquiry_data_len != sizeof(*inquiry_data)) {
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);
if (res != B_OK)
goto err3;
goto err1;
device = scsi_create_device(node, bus, target_id, target_lun);
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);
#ifdef USE_FAST_LOG
device->log = fast_log->start_log(device->name, scsi_device_events);
if (device->log == NULL) {
res = B_NO_MEMORY;
goto err;
goto err3;
}
#endif
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 (scsi_create_autosense_request(device) != B_OK) {
res = B_NO_MEMORY;
goto err;
goto err3;
}
}
// if this is an ATAPI device, we need an emulation buffer
if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) {
res = B_NO_MEMORY;
goto err;
goto err3;
}
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;
return B_OK;
err:
err3:
scsi_free_device(device);
err2:
pnp->unload_driver(pnp->get_parent(node));
err3:
if (inquiry_data != NULL)
free(inquiry_data);
pnp->uninit_driver(parent);
err1:
pnp->put_device_node(parent);
free(inquiry_data);
return res;
}
@@ -392,14 +401,15 @@ err3:
static status_t
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, "");
scsi_free_device(device);
// 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;
}
@@ -424,11 +434,10 @@ scsi_device_removed(device_node_handle node, scsi_device_info *device)
*/
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)
{
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_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
{ 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
acquire_sem(bus->scan_lun_lock);
// check whether device registered already
node = pnp->find_device(bus->node, attrs);
// check whether device registered already
node = NULL;
pnp->get_next_child_device(bus->node, &node, attrs);
SHOW_FLOW(3, "%p", node);
if (node != NULL) {
// there is one - get it
res = pnp->load_driver(node, NULL, &driver_interface,
res = pnp->init_driver(node, NULL, &driver_interface,
(void **)&device);
pnp->put_device_node(node);
} else {
// device doesn't exist yet - create a temporary one
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)
// device is registered
pnp->unload_driver(device->node);
pnp->uninit_driver(device->node);
else
// device is temporary
scsi_free_device(device);
@@ -534,9 +545,10 @@ scsi_device_interface scsi_device_module = {
std_ops
},
NULL, // supported devices
NULL, // register node
scsi_init_device,
(status_t (*)(void *)) scsi_uninit_device,
NULL,
(void (*)(device_node_handle, void *)) scsi_device_removed
},
+4 -7
View File
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI bus manager
@@ -14,16 +14,13 @@
locked_pool_interface *locked_pool;
device_manager_info *pnp;
fast_log_info *fast_log;
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 },
{ FAST_LOG_MODULE_NAME, (module_info **)&fast_log },
{}
};
_EXPORT
module_info *modules[] = {
(module_info *)&scsi_for_sim_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
sem_id dma_buffer_owner; // to be acquired before using DMA buffer
dma_buffer dma_buffer; // DMA buffer
#ifdef USE_FAST_LOG
fast_log_handle log; // fast log connection
#endif
char name[30]; // name for fast log entries
// buffer used for emulating SCSI commands
@@ -27,33 +27,20 @@
static status_t
scsi_controller_added(device_node_handle parent)
{
char *controller_name;
int path_id;
char *str, *controller_name;
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,
&controller_name, false) != B_OK) {
pnp->get_attr_string(parent, PNP_DRIVER_DRIVER, &str, false);
SHOW_ERROR(0, "Ignored controller managed by %s - controller name missing",
str);
dprintf("scsi: ignored controller - controller name missing\n");
return B_ERROR;
}
path_id = pnp->create_id(SCSI_PATHID_GENERATOR);
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);
free(controller_name);
return B_ERROR;
@@ -64,13 +51,10 @@ scsi_controller_added(device_node_handle parent)
{
device_attr attrs[] = {
// general information
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_BUS_TYPE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }},
// we are a bus
{ 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
// (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 }},
// 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 }
};
@@ -115,9 +99,10 @@ scsi_for_sim_interface scsi_for_sim_module =
std_ops
},
NULL, // supported devices
scsi_controller_added,
NULL,
NULL,
scsi_controller_added,
NULL
},
@@ -23,7 +23,7 @@
#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 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
module_std_ops(int32 op, ...)
{
@@ -180,7 +213,7 @@ module_std_ops(int32 op, ...)
module_dependency module_dependencies[] = {
{ 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 },
{}
};
@@ -195,10 +228,13 @@ static ide_controller_interface channel_interface = {
module_std_ops
},
(status_t (*)( device_node_handle , void *, void ** )) init_channel,
(status_t (*)( void * )) uninit_channel,
NULL,
(void (*)( device_node_handle , void * )) channel_removed
NULL, // supports device
NULL, // register device
(status_t (*)(device_node_handle, void *, void **))init_channel,
(status_t (*)(void *))uninit_channel,
(void (*)(device_node_handle, void *))channel_removed,
NULL, // cleanup
NULL, // get_paths
},
(status_t (*)(ide_channel_cookie,
@@ -226,17 +262,17 @@ static driver_module_info controller_interface = {
module_std_ops
},
(status_t (*)( device_node_handle, void *, void ** )) init_controller,
(status_t (*)( void * )) uninit_controller,
supports_device,
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 *)&controller_interface,
(module_info *)&channel_interface,
NULL
};
#endif
+53 -23
View File
@@ -30,7 +30,7 @@
#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:
// 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
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)
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;
channel = (channel_info *)malloc(sizeof(channel_info));
@@ -275,7 +296,7 @@ err:
free(channel);
err0:
pnp->unload_driver(pnp->get_parent(node));
pnp->uninit_driver(pnp->get_parent(node));
return res;
}
@@ -293,7 +314,7 @@ uninit_channel(channel_info *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);
@@ -301,20 +322,18 @@ uninit_channel(channel_info *channel)
}
// publish node of ide channel
/** publish node of an ide channel */
static status_t
publish_channel(device_node_handle parent, io_resource_handle *resources, uint16 command_block_base,
uint16 control_block_base, uint8 intnum, const char *name)
publish_channel(device_node_handle parent, io_resource_handle *resources,
uint16 command_block_base, uint16 control_block_base, uint8 intnum,
const char *name)
{
device_attr attrs[] = {
// info about ourself and our consumer
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_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
{ 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
// 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,
control_block_base, intnum, name);
}
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,
// so the pnp_manager tries each ISA driver in turn
@@ -386,7 +405,7 @@ scan_parent(device_node_handle node)
static void
channel_removed(device_node_handle node, channel_info *channel)
{
SHOW_FLOW0( 3, "" );
SHOW_FLOW0(3, "");
if (channel != NULL)
// 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
std_ops(int32 op, ...)
{
@@ -412,7 +442,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = {
{ 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
},
supports_device,
register_device,
(status_t (*)(device_node_handle, void *, void **)) init_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,
@@ -448,10 +481,7 @@ ide_controller_interface isa_controller_interface = {
(status_t (*)(ide_channel_cookie)) &finish_dma,
};
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = {
(module_info *)&isa_controller_interface,
NULL
};
#endif
@@ -22,11 +22,9 @@
#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_CONTROLLER_TYPE_NAME "promise tx2 controller"
static ide_for_controller_interface *ide;
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[] = {
// info about ourself and our consumer
{ PNP_DRIVER_DRIVER, 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 }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }},
// properties of this controller for ide bus manager
// there are always max. 2 devices
@@ -273,7 +268,7 @@ probe_controller(device_node_handle parent)
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;
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,
"Secondary Channel", &channels[1], false);
pnp->unload_driver(parent);
pnp->uninit_driver(parent);
return B_OK;
err:
pnp->unload_driver(parent);
pnp->uninit_driver(parent);
return res;
}
@@ -323,7 +318,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = {
{ 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 },
{}
};
@@ -338,9 +333,10 @@ static ide_controller_interface channel_interface = {
std_ops
},
NULL, // supported devices
NULL,
(status_t (*)( device_node_handle , void *, void ** )) init_channel,
(status_t (*)( void * )) uninit_channel,
NULL,
(void (*)( device_node_handle , void * )) channel_removed
},
@@ -369,17 +365,15 @@ static driver_module_info controller_interface = {
std_ops
},
NULL,
probe_controller,
(status_t (*)(device_node_handle, void *, void **)) init_controller,
(status_t (*)(void *)) uninit_controller,
probe_controller,
(void (*)(device_node_handle, void *)) controller_removed
};
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = {
(module_info *)&controller_interface,
(module_info *)&channel_interface,
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;
// 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);
if (res != B_OK)
goto err;
@@ -176,7 +176,7 @@ err:
static status_t
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);
return B_OK;
@@ -192,21 +192,9 @@ raw_device_added(device_node_handle node)
{
uint8 path_id, target_id, target_lun;
char name[100];
char *str;
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
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
@@ -221,18 +209,16 @@ raw_device_added(device_node_handle node)
// ready to register
{
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
// want to kick them out, we use concurrent "raw" connection
// (btw: this shows nicely that something goes wrong: one device
// and two drivers means begging for trouble)
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "raw" }},
// we want devfs on top of us
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
// we want devfs on top of us (who wouldn't?)
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
// tell which name we want to have in devfs
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
{ NULL }
@@ -258,7 +244,7 @@ std_ops(int32 op, ...)
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
},
NULL,
raw_device_added,
raw_init_device,
(status_t (*) (void *))raw_uninit_device,
raw_device_added,
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
// 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);
if (res != B_OK)
goto err2;
@@ -71,7 +71,7 @@ cd_init_device(device_node_handle node, void *user_cookie, void **cookie)
return B_OK;
err3:
pnp->unload_driver(pnp->get_parent(node));
pnp->uninit_driver(pnp->get_parent(node));
err2:
err1:
free(device);
@@ -83,7 +83,7 @@ status_t
cd_uninit_device(cd_device_info *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);
return B_OK;
@@ -98,7 +98,6 @@ cd_uninit_device(cd_device_info *device)
status_t
cd_device_added(device_node_handle node)
{
char *str = NULL;
uint8 device_type;
scsi_res_inquiry *device_inquiry = NULL;
size_t inquiry_len;
@@ -107,11 +106,6 @@ cd_device_added(device_node_handle node)
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
if( pnp->get_attr_uint8( node, SCSI_DEVICE_TYPE_ITEM,
&device_type, true ) != B_OK ||
@@ -145,11 +139,10 @@ cd_device_added(device_node_handle node)
// ready to register
{
device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_CD_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: BLKDEV_TYPE_NAME }},
// we always want blkdev on top of us
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
// tell blkdev whether the device is removable
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_CD_MODULE_NAME }},
// we always want blkman on top of us
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
// tell blkman whether the device is removable
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
// tell which name we want to have in devfs
{ 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);
free(name);
free(str);
free(device_inquiry);
return res;
}
err:
free(str);
free(device_inquiry);
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;
// 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);
if (res != B_OK)
goto err2;
@@ -71,7 +71,7 @@ das_init_device(device_node_handle node, void *user_cookie, void **cookie)
err4:
scsi_periph->unregister_device(device->scsi_periph_device);
err3:
pnp->unload_driver(pnp->get_parent(node));
pnp->uninit_driver(pnp->get_parent(node));
err2:
err1:
free(device);
@@ -83,7 +83,7 @@ status_t
das_uninit_device(das_device_info *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);
return B_OK;
@@ -98,18 +98,12 @@ das_uninit_device(das_device_info *device)
status_t
das_device_added(device_node_handle node)
{
char *str = NULL;
scsi_res_inquiry *device_inquiry = NULL;
uint8 device_type;
size_t inquiry_len;
char *name;
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
if (pnp->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK
|| device_type != scsi_dev_direct_access)
@@ -141,11 +135,10 @@ das_device_added(device_node_handle node)
// ready to register
{
device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: BLKDEV_TYPE_NAME }},
// we always want blkdev on top of us
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
// tell blkdev whether the device is removable
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }},
// we always want blkman on top of us
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
// tell blkman whether the device is removable
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
// tell which name we want to have in devfs
{ 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);
free(name);
free(str);
free(device_inquiry);
return res;
}
err:
free(str);
free(device_inquiry);
return B_ERROR;
@@ -16,7 +16,9 @@
#include "scsi_dsk_int.h"
#include <scsi.h>
#include <string.h>
#include <stdlib.h>
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
std_ops(int32 op, ...)
{
@@ -239,7 +272,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = {
{ SCSI_PERIPH_MODULE_NAME, (module_info **)&scsi_periph },
{ 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
},
das_supports_device,
das_device_added,
das_init_device,
(status_t (*) (void *))das_uninit_device,
das_device_added,
NULL
NULL, // remove device
NULL, // cleanup device
das_get_paths,
},
(status_t (*)(blkdev_device_cookie, blkdev_handle_cookie *)) &das_open,
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI Disk Driver
@@ -17,6 +17,6 @@
#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
blkman_probe(device_node_handle parent)
blkman_register_device(device_node_handle parent)
{
char *str;
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
{
device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
// 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" }},
{ NULL }
};
@@ -505,7 +491,7 @@ blkman_init_device(device_node_handle node, void *user_cookie, void **cookie)
device->params = params;
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);
if (res != B_OK)
goto err4;
@@ -525,7 +511,7 @@ err2:
free(device);
err1:
free(name);
pnp->unload_driver(pnp->get_parent(node));
pnp->uninit_driver(pnp->get_parent(node));
return res;
}
@@ -533,7 +519,7 @@ err1:
static status_t
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);
benaphore_destroy(&device->lock);
@@ -614,7 +600,7 @@ std_ops(int32 op, ...)
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 },
{}
};
@@ -628,11 +614,14 @@ pnp_devfs_driver_info blkman_module = {
std_ops
},
NULL, // supports device
blkman_register_device,
blkman_init_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,
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Fast logging facilities.
@@ -568,7 +568,7 @@ fast_log_std_ops(int32 op, ...)
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;
device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: FAST_LOG_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: FAST_LOG_DEVFS_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "fast_log" }},
{ 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
},
NULL,
NULL,
fast_log_devfs_init_device,
fast_log_devfs_uninit_device,
NULL,
NULL,
NULL,
},
fast_log_devfs_open,
@@ -301,17 +301,18 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel)
if (status.active) {
SHOW_ERROR0( 2, "DMA transfer aborted" );
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 too large" );
return B_DEV_DATA_OVERRUN;
} else
return B_OK;
SHOW_ERROR0( 2, "DMA transfer: buffer underrun" );
return B_DEV_DATA_UNDERRUN;
}
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)
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;
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:
delete_area(channel->prd_area);
err2:
pnp->unload_driver(pnp->get_parent(node));
pnp->uninit_driver(pnp->get_parent(node));
err:
free(channel);
@@ -410,7 +411,7 @@ ide_adapter_uninit_channel(ide_adapter_channel_info *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);
free(channel);
@@ -441,14 +442,10 @@ ide_adapter_publish_channel(device_node_handle controller_node,
{
device_attr attrs[] = {
// info about ourself and our consumer
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: channel_module_name }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }},
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: channel_module_name }},
{ B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "IDE PCI" }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "IDE PCI" }},
// disable automatic rescan as we register channels manually
{ PNP_DRIVER_NEVER_RESCAN, B_UINT8_TYPE, { ui8 : 1 }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
// private data to identify channel
{ 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 }
};
SHOW_FLOW0( 2, "" );
SHOW_FLOW0(2, "");
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)
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;
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
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);
@@ -609,10 +606,7 @@ ide_adapter_publish_controller(device_node_handle parent, uint16 bus_master_base
{
device_attr attrs[] = {
// info about ourself and our consumer
{ PNP_DRIVER_DRIVER, 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 }},
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: controller_driver }},
// properties of this controller for ide bus manager
// 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, "" );
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;
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,
intnum, false, "Secondary Channel", &channels[1], supports_compatibility_mode);
pnp->unload_driver(parent);
pnp->uninit_driver(parent);
return B_OK;
err:
pnp->unload_driver(parent);
pnp->uninit_driver(parent);
return res;
}
@@ -752,7 +746,7 @@ std_ops(int32 op, ...)
module_dependency module_dependencies[] = {
{ 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_finish_dma,
ide_adapter_inthand,
ide_adapter_init_channel,
@@ -797,11 +790,7 @@ static ide_adapter_interface adapter_interface = {
ide_adapter_probe_controller
};
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = {
&adapter_interface.info,
NULL
};
#endif
@@ -1,7 +1,7 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI Peripheral Driver
@@ -128,7 +128,7 @@ std_ops(int32 op, ...)
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
};
#if !_BUILDING_kernel && !BOOT
_EXPORT
scsi_periph_interface *modules[] = {
&scsi_periph_module,
NULL
};
#endif
+53 -12
View File
@@ -168,19 +168,19 @@ pnp_get_attr_string_nolock(device_node_handle node, const char *name,
status_t
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;
status_t status;
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) {
void *tmp_data = malloc(*len);
void *tmp_data = malloc(*length);
if (tmp_data != NULL) {
memcpy(tmp_data, orig_data, *len);
memcpy(tmp_data, orig_data, *length);
*data = tmp_data;
} else
status = B_NO_MEMORY;
@@ -194,18 +194,61 @@ 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,
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);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*data = attr->attr.value.raw.data;
*len = attr->attr.value.raw.len;
*length = attr->attr.value.raw.length;
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
void
@@ -260,15 +303,15 @@ pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out)
break;
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) {
res = B_NO_MEMORY;
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,
src->value.raw.len);
src->value.raw.length);
break;
default:
@@ -448,10 +491,8 @@ static bool
is_fixed_attribute(const char *name)
{
static const char *forbidden_list[] = {
PNP_DRIVER_DRIVER, // never change driver
PNP_DRIVER_TYPE, // never change type
B_DRIVER_MODULE, // never change driver
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;
@@ -26,7 +26,7 @@
#endif
device_node_info *gNodeList;
device_node_info *gRootNode;
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;
#if 0
void
check_settings()
static int
dump_device_nodes(int argc, char **argv)
{
void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
disable_useraddons = get_driver_boolean_parameter(settings, "disableuseraddons", 0, 1);
unload_driver_settings(settings);
dm_dump_node(gRootNode, 0);
return 0;
}
#endif
static status_t
@@ -70,7 +66,7 @@ std_ops(int32 op, ...)
device_manager_info gDeviceManagerModule = {
{
DEVICE_MANAGER_MODULE_NAME,
B_DEVICE_MANAGER_MODULE_NAME,
0,
std_ops
},
@@ -78,20 +74,21 @@ device_manager_info gDeviceManagerModule = {
pnp_load_driver,
pnp_unload_driver,
pnp_rescan,
dm_rescan,
pnp_register_device,
pnp_unregister_device,
dm_register_node,
dm_unregister_node,
pnp_acquire_io_resources,
pnp_release_io_resources,
dm_get_next_child_node,
dm_get_parent,
dm_put_node,
pnp_find_device,
dm_acquire_io_resources,
dm_release_io_resources,
pnp_create_id,
pnp_free_id,
dm_create_id,
dm_free_id,
pnp_get_parent,
pnp_get_attr_uint8,
pnp_get_attr_uint16,
pnp_get_attr_uint32,
@@ -102,7 +99,8 @@ device_manager_info gDeviceManagerModule = {
pnp_get_next_attr,
pnp_release_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"));
status = id_generator_init();
status = dm_init_id_generator();
if (status < B_OK) {
panic("could not initialize ID generator\n");
return status;
}
status = nodes_init();
status = dm_init_nodes();
if (status < B_OK) {
panic("could not initialize device nodes\n");
return status;
@@ -141,14 +139,14 @@ device_manager_init(struct kernel_args *args)
io_mem_list = io_port_list = isa_dma_list = NULL;
pnp_fs_emulation_nesting = 0;
pnp_root_init_root();
dm_init_root_node();
{
// dump root node
device_node_info *node = gNodeList;
device_node_info *node = gRootNode;
while (node && node->parent != NULL)
node = node->parent;
dump_device_node_info(node, 0);
dm_dump_node(node, 0);
}
// build initial device tree; register all root bus_managers
@@ -164,6 +162,7 @@ device_manager_init(struct kernel_args *args)
}
#endif
add_debugger_command("dm_tree", &dump_device_nodes, "dump device node tree");
return B_OK;
}
@@ -30,17 +30,15 @@
#define SYSTEM_MODULES_DIR "/boot/beos/add-ons/kernel/"
#define COMMON_MODULES_DIR "/boot/home/config/add-ons/kernel/"
#define PNP_BOOT_LINKS "pnp_bootlinks"
// info about ID generator
typedef struct id_generator {
struct list_link link;
struct id_generator *prev, *next;
int ref_count;
char *name;
uint32 num_ids;
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
int32 ref_count;
char *name;
uint32 num_ids;
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
} id_generator;
@@ -60,11 +58,18 @@ typedef struct 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
// whenever you do something in terms of nodes, grab it
extern benaphore gNodeLock;
// list of nodes (includes removed devices!)
extern device_node_info *gNodeList;
// root node
extern device_node_info *gRootNode;
// true, if user addons are disabled via safemode
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,
const void **data, size_t *len, bool recursive);
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_get_next_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);
// 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
status_t pnp_load_driver(device_node_handle node, void *user_cookie,
driver_module_info **interface, void **cookie);
status_t pnp_unload_driver(device_node_handle 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
int32 pnp_create_id(const char *name);
status_t pnp_free_id(const char *name, uint32 id);
extern status_t id_generator_init(void);
int32 dm_create_id(const char *name);
status_t dm_free_id(const char *name, uint32 id);
extern status_t dm_init_id_generator(void);
// io_resources.c
status_t pnp_acquire_io_resources(io_resource *resources, io_resource_handle *handles);
status_t pnp_release_io_resources(const io_resource_handle *handles);
void pnp_assign_io_resources(device_node_info *node, const io_resource_handle *handles);
void pnp_release_node_resources(device_node_info *node);
status_t dm_acquire_io_resources(io_resource *resources, io_resource_handle *handles);
status_t dm_release_io_resources(const io_resource_handle *handles);
void dm_assign_io_resources(device_node_info *node, const io_resource_handle *handles);
void dm_release_node_resources(device_node_info *node);
// 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);
void pnp_create_node_links(device_node_info *node, device_node_info *parent);
void pnp_add_node_ref(device_node_info *node);
void pnp_remove_node_ref(device_node_info *node);
void pnp_remove_node_ref_nolock(device_node_info *node);
device_node_handle pnp_find_device(device_node_handle parent, const device_attr *attrs);
device_node_handle pnp_get_parent(device_node_handle node);
void dump_device_node_info(device_node_info *node, int32 level);
extern status_t nodes_init(void);
void dm_add_child_node(device_node_info *node, device_node_info *parent);
void dm_get_node_nolock(device_node_info *node);
void dm_get_node(device_node_info *node);
void dm_put_node_nolock(device_node_info *node);
void dm_dump_node(device_node_info *node, int32 level);
status_t dm_init_nodes(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
status_t pnp_notify_probe_by_module(device_node_info *node,
const char *consumer_name);
void pnp_notify_unregistration(device_node_info *notify_list);
status_t dm_notify_unregistration(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_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);
// probe.c
status_t pnp_notify_fixed_consumers(device_node_handle node);
status_t pnp_notify_dynamic_consumers(device_node_info *node);
// probe.cpp
status_t dm_register_child_device(device_node_info *node, const char *childName);
status_t dm_register_fixed_child_devices(device_node_info *node);
status_t dm_register_dynamic_child_devices(device_node_info *node);
// registration.c
status_t pnp_register_device(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *resources, device_node_handle *node);
status_t pnp_unregister_device(device_node_handle node);
void pnp_unregister_node_rec(device_node_info *node, device_node_info **dependency_list);
status_t dm_register_node(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *resources, device_node_handle *_newNode);
status_t dm_unregister_node(device_node_handle node);
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
extern void pnp_root_init_root(void);
extern void pnp_root_destroy_root(void);
extern void pnp_root_rescan_root(void);
void dm_init_root_node(void);
// scan.c
status_t pnp_rescan(device_node_handle node, uint32 depth);
status_t pnp_rescan_int(device_node_info *node, uint32 depth,
bool ignore_fixed_consumers);
status_t pnp_initial_scan(device_node_info *node);
status_t dm_rescan(device_node_handle node);
status_t dm_register_child_devices(device_node_info *node);
#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
* (loader_lock must be hold)
*/
@@ -173,49 +76,48 @@ err:
static status_t
load_driver_int(device_node_info *node, void *user_cookie)
{
char *module_name;
driver_module_info *driver;
char *moduleName;
void *cookie;
status_t res;
status_t status;
TRACE(("load_driver_int()\n"));
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false);
if (res != B_OK)
return res;
status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
if (status != B_OK)
return status;
TRACE(("%s\n", module_name));
TRACE(("%s\n", moduleName));
res = get_module(module_name, (module_info **)&driver);
if (res < B_OK) {
dprintf("Cannot load module %s\n", module_name);
goto err;
status = get_module(moduleName, (module_info **)&driver);
if (status < B_OK) {
dprintf("Cannot load module %s\n", moduleName);
goto err1;
}
if (driver->init_device == NULL) {
dprintf("Driver %s has no init_device hook\n", module_name);
res = B_ERROR;
if (driver->init_driver == NULL) {
dprintf("Driver %s has no init_driver hook\n", moduleName);
status = B_ERROR;
goto err2;
}
res = driver->init_device(node, user_cookie, &cookie);
if (res < B_OK) {
dprintf("init device failed (node %p, %s): %s\n", node, module_name, strerror(res));
status = driver->init_driver(node, user_cookie, &cookie);
if (status < B_OK) {
dprintf("init driver failed (node %p, %s): %s\n", node, moduleName, strerror(status));
goto err2;
}
node->driver = driver;
node->cookie = cookie;
free(module_name);
free(moduleName);
return B_OK;
err2:
put_module(module_name);
err:
free(module_name);
return res;
put_module(moduleName);
err1:
free(moduleName);
return status;
}
@@ -257,12 +159,6 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
// make sure noone else load/unloads/notifies the driver
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) {
// device got lost meanwhile
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) {
// everything went fine - increase load counter
++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 {
// loading failed or device got removed - restore reference count;
// but first (i.e. as long as ref_count is increased) get
// rid of waiting children
pnp_probe_waiting_children_nolock(node);
pnp_remove_node_ref_nolock(node);
dm_put_node_nolock(node);
}
} else {
// 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;
TRACE(("load_driver: Success \"%s\"\n",
((struct module_info *)(*interface))->name));
((struct module_info *)node->driver)->name));
} else {
TRACE(("load_driver: Failure (%s)\n", strerror(res)));
}
@@ -338,26 +229,26 @@ static status_t
unload_driver_int(device_node_info *node)
{
driver_module_info *driver = node->driver;
char *module_name;
status_t res;
char *moduleName;
status_t status;
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false);
if (res != B_OK)
return res;
status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
if (status != B_OK)
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
TRACE(("Driver %s has no uninit_device hook\n", module_name));
res = B_ERROR;
goto err;
TRACE(("Driver %s has no uninit_device hook\n", moduleName));
status = B_ERROR;
goto out;
}
res = driver->uninit_device(node->cookie);
if (res != B_OK) {
TRACE(("Failed to uninit driver %s (%s)\n", module_name, strerror(res)));
goto err;
status = driver->uninit_driver(node->cookie);
if (status != B_OK) {
TRACE(("Failed to uninit driver %s (%s)\n", moduleName, strerror(status)));
goto out;
}
// 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);
}
put_module(module_name);
put_module(moduleName);
free(module_name);
return B_OK;
err:
free(module_name);
return res;
out:
free(moduleName);
return status;
}
@@ -428,7 +316,7 @@ pnp_unload_driver(device_node_handle node)
// everything is fine, so decrease load_count ...
--node->load_count;
// ... and reference count
pnp_remove_node_ref_nolock(node);
dm_put_node_nolock(node);
} else {
// unloading failed: leave loaded in memory forever
// 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
--node->load_count;
// 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;
}
@@ -159,7 +159,7 @@ release_generator(id_generator *generator)
status_t
id_generator_init(void)
dm_init_id_generator(void)
{
list_init(&sGenerators);
return benaphore_init(&sGeneratorLock, "id generator");
@@ -167,13 +167,13 @@ id_generator_init(void)
// #pragma mark -
// Public API
// Public module API
/** Create automatic ID */
int32
pnp_create_id(const char *name)
dm_create_id(const char *name)
{
id_generator *generator;
int32 id;
@@ -203,7 +203,7 @@ pnp_create_id(const char *name)
/** Free automatically generated ID */
status_t
pnp_free_id(const char *name, uint32 id)
dm_free_id(const char *name, uint32 id)
{
id_generator *generator;
+99 -87
View File
@@ -67,17 +67,17 @@ validate_io_resource(io_resource *src)
switch (src->type) {
case IO_MEM:
if (src->base + src->len < src->base)
if (src->base + src->length < src->base)
return B_BAD_VALUE;
break;
case IO_PORT:
if ((uint16)src->base != src->base
|| (uint16)src->len != src->len
|| (uint16)(src->base + src->len) < src->base)
|| (uint16)src->length != src->length
|| (uint16)(src->base + src->length) < src->base)
return B_BAD_VALUE;
break;
case ISA_DMA_CHANNEL:
if (src->base > 8 || src->len != 1)
if (src->base > 8 || src->length != 1)
return B_BAD_VALUE;
break;
@@ -107,7 +107,7 @@ alloc_io_resource_info(io_resource *src, io_resource_info **dest_out)
dest->resource.type = src->type;
dest->resource.base = src->base;
dest->resource.len = src->len;
dest->resource.length = src->length;
*dest_out = dest;
return B_OK;
@@ -123,15 +123,15 @@ acquire_range(io_resource_info **list, io_resource_info *resource)
{
io_resource_info *cur;
uint32 base = resource->resource.base;
uint32 len = resource->resource.len;
uint32 length = resource->resource.length;
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) {
// 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) {
&& cur->resource.base + length - 1 <= base + length - 1) {
device_node_info *owner = cur->owner;
TRACE(("collision\n"));
@@ -180,18 +180,19 @@ acquire_range(io_resource_info **list, io_resource_info *resource)
static void
free_io_resource_info(io_resource_info *resource)
{
TRACE(("free_io_resource_info"));
TRACE(("free_io_resource_info()\n"));
free(resource);
}
// acquire I/O resource
// a I/O resource info structure is allocated and added to
// appropriate resource list (i.e. mem/port/channel) plus
// all colliding resources (including ours) are marked blocked;
// returns B_WOULD_BLOCK on collision with temporary allocation;
// node_lock must be hold
/** Acquire I/O resource.
* An I/O resource info structure is allocated and added to
* appropriate resource list (i.e. mem/port/channel) plus
* all colliding resources (including ours) are marked blocked;
* returns B_WOULD_BLOCK on collision with temporary allocation;
* gNodeLock must be hold.
*/
static status_t
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;
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);
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;
uint32 base = resource->resource.base;
uint32 len = resource->resource.len;
uint32 length = resource->resource.length;
TRACE(("release_range()\n"));
@@ -282,8 +284,8 @@ release_range(io_resource_info **list, io_resource_info *resource, io_resource_i
// ignore ourselves
continue;
// we need the "base + len - 1" trick to avoid wrap around at 4 GB
if (cur->resource.base >= base && cur->resource.base + len - 1 <= base + len - 1) {
// we need the "base + length - 1" trick to avoid wrap around at 4 GB
if (cur->resource.base >= base && cur->resource.base + length - 1 <= base + length - 1) {
device_node_info *owner = cur->owner;
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
static void
@@ -461,7 +423,7 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
{
io_resource_info *cur;
uint32 base = resource->resource.base;
uint32 len = resource->resource.len;
uint32 length = resource->resource.length;
do {
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)
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) {
&& cur->resource.base + length - 1 <= base + length - 1) {
device_node_handle owner = cur->owner;
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
// (its resources are freed by the next remove_node_ref call)
pnp_unregister_device(owner);
dm_unregister_node(owner);
benaphore_lock(&gNodeLock);
pnp_remove_node_ref_nolock(owner);
dm_put_node_nolock(owner);
// restart loop as resource list may have changed meanwhile
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;
// colliding devices are unregistered
/** unblock other temporary allocations so they can retry
* 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
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;
@@ -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
// node_lock 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
/** release I/O resources of a device node and set list to NULL;
* users previously blocked by our resource alloction are notified;
* gNodeLock must be hold
*/
void
pnp_release_node_resources(device_node_info *node)
dm_release_node_resources(device_node_info *node)
{
io_resource_handle *resource;
@@ -568,3 +536,47 @@ pnp_release_node_resources(device_node_info *node)
*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;
// increase ref_count of node
void
pnp_add_node_ref(device_node_info *node)
static void
put_level(int32 level)
{
TRACE(("add_node_ref(%p)\n", node));
if (node == NULL)
return;
benaphore_lock(&gNodeLock);
node->ref_count++;
benaphore_unlock(&gNodeLock);
while (level-- > 0)
dprintf(" ");
}
// free attributes of node
// if an attribute is still in use, it's deletion is postponed
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);
}
/** free attributes of node
* if an attribute is still in use, it's deletion is postponed
*/
static void
free_node_attrs(device_node_info *node)
@@ -93,16 +119,14 @@ free_node_resources(device_node_info *node)
static void
free_node(device_node_info *node)
{
const char *generator_name, *driver_name, *type;
const char *generator_name, *driver_name;
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 = "?";
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_TYPE, &type, false) != B_OK)
type = "?";
TRACE(("free_node(node: %p, driver: %s, type: %s)\n", node, driver_name, type));
TRACE(("free_node(node: %p, driver: %s)\n", node, driver_name));
// free associated auto ID, if requested
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) {
TRACE(("Cannot find corresponding auto_id of generator %s", generator_name));
} else
pnp_free_id(generator_name, auto_id);
dm_free_id(generator_name, auto_id);
}
pnp_release_node_resources(node);
//list_remove_link(node);
REMOVE_DL_LIST( node, gNodeList, );
dm_release_node_resources(node);
delete_sem(node->hook_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
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;
// initially, ref_count is one to make sure node won't get destroyed by mistake
// #pragma mark -
// 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
pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
device_node_info **new_node)
dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
device_node_info **_node)
{
device_node_info *node;
status_t res;
TRACE(("pnp_alloc_node()\n"));
node = calloc(1, sizeof(*node));
if (node == NULL)
return B_NO_MEMORY;
@@ -269,11 +244,16 @@ pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
if (res < 0)
goto err4;
list_init(&node->children);
node->parent = NULL;
node->rescan_depth = 0;
node->registered = false;
#if 0
node->verifying = false;
node->redetected = false;
node->init_finished = false;
#endif
node->ref_count = 1;
node->load_count = 0;
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->load_block_count = 0;
node->loading = 0;
node->defer_probing = 0;
node->unprobed_children = NULL;
// make public (well, almost: it's not officially registered yet)
benaphore_lock(&gNodeLock);
TRACE(("dm_allocate_node(): new node %p\n", node));
ADD_DL_LIST_HEAD(node, gNodeList, );
benaphore_unlock(&gNodeLock);
*new_node = node;
*_node = node;
return B_OK;
@@ -309,45 +282,91 @@ err:
}
// create links to parent node
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)
return;
benaphore_lock(&gNodeLock);
TRACE(("Adding parent link"));
// parent must not be destroyed
// parent must not be destroyed as long as it has children
parent->ref_count++;
node->parent = parent;
// tell parent about us, so we get unregistered automatically if parent
// gets unregistered
ADD_DL_LIST_HEAD(node, parent->children, siblings_ );
list_add_item(&parent->children, node);
benaphore_unlock(&gNodeLock);
}
// public: get parent of node
device_node_handle
pnp_get_parent(device_node_handle node)
void
dm_get_node_nolock(device_node_info *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
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;
@@ -366,58 +385,8 @@ pnp_find_device(device_node_info *parent, const device_attr *attrs)
continue;
for (attr = attrs; attr && attr->name; ++attr) {
bool equal = true;
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)
device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
break;
}
@@ -439,52 +408,14 @@ err:
return found_node;
}
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);
}
#endif
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)
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 : "---");
dump_attribute(node->attributes, level);
dump_device_node_info(node->children, level + 1);
dump_device_node_info(node->siblings_next, level);
while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
dm_dump_node(child, level + 1);
}
}
status_t
nodes_init(void)
dm_init_nodes(void)
{
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
/** 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 */
static status_t
notify_device_removed(device_node_info *node)
status_t
dm_notify_unregistration(device_node_info *node)
{
driver_module_info *driver;
bool loaded;
@@ -70,19 +39,21 @@ notify_device_removed(device_node_info *node)
void *cookie;
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)
return res;
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);
#if 0
// don't notify driver if it doesn't know that the device was
// published
if (!node->init_finished)
goto skip;
#endif
// don't take node->loading into account - we want to know
// 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
* load/unload/notification hook is called
*/
+572 -119
View File
@@ -44,8 +44,16 @@ struct path_entry {
char *path;
dev_t device;
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
const char *pnp_registration_dirs[2] = {
@@ -62,6 +70,8 @@ static const char *kModulePaths[] = {
NULL
};
extern dev_t gBootDevice;
// from fs/vfs.cpp
class DirectoryIterator {
public:
@@ -207,6 +217,136 @@ DirectoryIterator::AddPath(const char *basePath, const char *subPath)
// #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
* fileName - file name of consumer
* (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, type, B_PATH_NAME_LENGTH);
res = pnp_notify_probe_by_module(node, module_name);
res = dm_register_child_device(node, module_name);
err2:
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
* 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
*/
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,
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;
* further, remove quotes from directory
* pattern - pattern of consumer name
@@ -476,7 +616,7 @@ find_normal_consumer(device_node_info *node, const char *dir,
*/
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 *str, *dest;
@@ -547,7 +687,7 @@ preprocess_consumer_names(const char *pattern, char *buffer,
*/
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)
{
status_t status;
@@ -555,7 +695,7 @@ notify_dynamic_consumer(device_node_info *node, const char *bus,
char *filename_pattern;
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));
if (pattern == NULL)
@@ -566,14 +706,14 @@ notify_dynamic_consumer(device_node_info *node, const char *bus,
if (buffers == NULL)
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);
if (status < B_OK)
goto err;
if (!*has_normal_driver) {
// 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);
if (status != B_OK && status != B_NAME_NOT_FOUND)
// only abort if there was a "real" problem;
@@ -600,6 +740,7 @@ err:
free(buffers);
return status;
}
#endif
static path_entry *
@@ -639,19 +780,22 @@ load_driver(const char *path)
name++;
// 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 *);
const char **(*publish_devices)(void);
uint32 *api_version;
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) {
dprintf("%s: mandatory driver symbol(s) missing!\n", name);
status = B_BAD_VALUE;
goto error1;
}
// test for init_hardware() and call it
// Init the driver
if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT,
(void **)&init_hardware) == B_OK
&& (status = init_hardware()) != B_OK) {
@@ -660,19 +804,6 @@ load_driver(const char *path)
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,
(void **)&init_driver) == B_OK
&& (status = init_driver()) != B_OK) {
@@ -681,7 +812,13 @@ load_driver(const char *path)
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
// 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();
if (devicePaths == NULL) {
dprintf("%s: publish_devices() returned NULL.\n", name);
@@ -702,7 +839,6 @@ load_driver(const char *path)
status = B_ERROR; // whatever...
error3:
{
status_t (*uninit_driver)(void);
@@ -712,12 +848,12 @@ error3:
}
error2:
{
status_t (*uninit_hardware)(void);
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
(void **)&uninit_hardware) == B_OK)
uninit_hardware();
}
{
status_t (*uninit_hardware)(void);
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
(void **)&uninit_hardware) == B_OK)
uninit_hardware();
}
error1:
/* If we've gotten here then the driver will be unloaded and an
* 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
try_drivers(struct list &list)
try_drivers(struct list &list, bool tryBusDrivers)
{
path_entry *entry;
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);
if (image >= 0) {
// 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 -
// 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
* errors returned by consumers aren't reported, only problems
* like malformed consumer patterns
*/
status_t
pnp_notify_dynamic_consumers(device_node_info *node)
dm_register_dynamic_child_devices(device_node_info *node)
{
#if 0
char *buffer;
char *bus;
status_t status = B_OK;
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;
TRACE((" Search bus: \"%s\"\n", bus));
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
if (buffer == NULL) {
status = B_NO_MEMORY;
goto err;
}
if (gBootDevice < 0) {
// there is no boot device yet, we have to scan the already
// loaded and built-in modules
struct list modules;
list_init(&modules);
// first, append nothing, then "/0", "/1" etc.
for (i = -1; ; ++i) {
bool noSpecificDriver = false;
char *consumer;
status = get_loaded_modules(&modules, bus, NULL);
if (status != B_OK)
return status;
strcpy(buffer, PNP_DRIVER_CONSUMER_MAPPING);
if (i >= 0)
sprintf(buffer + strlen( buffer ), "/%ld", i);
register_supporting_child_devices(node, &modules);
return B_OK;
} 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
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
// first, append nothing, then "/0", "/1" etc.
for (i = -1; ; ++i) {
bool noSpecificDriver = false;
char *consumer;
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;
}
}
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;
}
#endif
}
#if 0
if (found == 0) {
// no requirement for a special mapping, so we're just scanning the bus directory
bool noSpecificDriver = false;
status = notify_dynamic_consumer(node, bus, NULL, &noSpecificDriver);
status = register_dynamic_child_device(node, bus, NULL, &noSpecificDriver);
}
// supposed to go through
free(buffer);
#endif
err:
free(bus);
return status;
#else
return B_OK;
#endif
}
/** Notify fixed consumers that device was added; in contrast to dynamic
* consumers, errors reported by fixed consumers are not ignored but
* returned.
/** Register all fixed child devices of of the given \a node; in contrast
* to dynamic child devices, errors reported by fixed child devices are
* not ignored but returned, and regarded critical.
*/
status_t
pnp_notify_fixed_consumers(device_node_info *node)
dm_register_fixed_child_devices(device_node_info *node)
{
int i;
char *buffer;
TRACE(("dm_register_fixed_child_devices(node = %p)\n", node));
TRACE(("pnp_notify_fixed_consumers(node = %p)\n", node));
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
char *buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
if (buffer == NULL)
return B_NO_MEMORY;
// first, append nothing, then "/0", "/1" etc.
for (i = -1; ; ++i) {
char *consumer;
for (int32 i = -1; ; ++i) {
char *childName;
strcpy(buffer, PNP_DRIVER_FIXED_CONSUMER);
strcpy(buffer, B_DRIVER_FIXED_CHILD);
if (i >= 0)
sprintf(buffer + strlen(buffer), "/%d", i);
sprintf(buffer + strlen(buffer), "/%ld", i);
// 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;
TRACE(("Consumer %d: %s\n", i, consumer));
TRACE(("Consumer %ld: %s\n", i, childName));
if (pnp_notify_probe_by_module(node, consumer) != B_OK) {
dprintf("Cannot notify fixed consumer %s\n", consumer);
if (dm_register_child_device(node, childName) != B_OK) {
dprintf("Cannot register fixed child device %s\n", childName);
// report error if fixed consumers couldn't be loaded
// 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);
return B_NAME_NOT_FOUND;
}
free(consumer);
free(childName);
}
free(buffer);
@@ -899,49 +1315,65 @@ pnp_notify_fixed_consumers(device_node_info *node)
}
status_t
probe_for_device_type(const char *type)
static status_t
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
// or notify bus managers to get one
status_t status = B_OK;
// build list of potential drivers for that type
struct list drivers;
list_init(&drivers);
char devType[64];
snprintf(devType, sizeof(devType), "drivers/dev%s%s", type[0] ? "/" : "", type);
if (gBootDevice < 0) {
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;
KPath path;
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)) {
// We need to make sure that drivers in ie. "audio/raw/" can
// be found as well - therefore, we must make sure that "audio"
// exists on /dev.
if (type[0])
devfs_publish_directory(type);
int32 length = strlen("drivers/dev/");
if (!strncmp(type, "drivers/dev/", length))
devfs_publish_directory(type + length);
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);
}
@@ -959,13 +1391,23 @@ probe_for_device_type(const char *type)
struct list driversForBus;
list_init(&driversForBus);
dprintf("bus: %s\n", path.Leaf());
while (busIterator.GetNext(path, stat) == B_OK) {
path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, stat.st_ino);
if (entry == NULL)
continue;
// we found the driver here, so we should check it
list_remove_link(&entry->link);
entry->busses++;
// 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);
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: ask bus manager for driver (via mapping)
// 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... :)
try_drivers(drivers);
try_drivers(drivers, false);
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
// decrease ref_count of unregistered nodes, specified by <node_list>
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()
/** mark node being registered, so it can be accessed via load_driver() */
static status_t
mark_node_registered(device_node_info *node)
@@ -52,7 +37,7 @@ mark_node_registered(device_node_info *node)
status_t res;
TRACE(("mark_node_registered(%p)\n", node));
benaphore_lock(&gNodeLock);
if (node->parent && !node->parent->registered) {
@@ -65,15 +50,15 @@ mark_node_registered(device_node_info *node)
}
benaphore_unlock(&gNodeLock);
return res;
}
// check whether device is redetected and remove
// any device that is on same connection.
// *redetected is set true if device is already registered;
// the node must not yet be linked into parent node's children list
#if 0
/** Checks whether the device is redetected and removes any other
* device that is on same connection and has the same device identifier.
* \a redetected is set true if device is already registered;
* the node must not yet be linked into parent node's children list
*/
static status_t
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
// noone else (un)-registers a conflicting note during the tests
// no one else (un)-registers a conflicting note during the tests
benaphore_lock(&gNodeLock);
{
@@ -203,10 +188,10 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
if (unregister_sibling) {
// increase ref_count to make sure node still exists
// when node_lock has been released
// when gNodeLock has been released
++sibling->ref_count;
benaphore_unlock(&gNodeLock);
pnp_unregister_device(sibling);
pnp_remove_node_ref_nolock(sibling);
} else
@@ -214,283 +199,184 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
return B_OK;
err:
err:
benaphore_unlock(&gNodeLock);
return res;
}
#endif
// postpone searching for consumers if necessary
// return: true, if postponed
static bool
pnp_postpone_probing(device_node_info *node)
static status_t
push_node_on_stack(struct list *list, 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
if (node->parent == NULL || !node->parent->defer_probing) {
benaphore_unlock(&gNodeLock);
return false;
}
// 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;
dm_get_node_nolock(node);
entry->node = node;
list_add_item(list, entry);
return B_OK;
}
// public: 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
static device_node_info *
pop_node_from_stack(struct list *list)
{
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
pnp_register_device(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *io_resources, device_node_handle *node)
dm_register_node(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *ioResources, device_node_handle *_node)
{
device_node_info *node_inf;
bool redetected;
status_t res = B_OK;
device_node_info *newNode;
char *driverName = NULL;
status_t status = B_OK;
struct list stack;
res = pnp_alloc_node(attrs, io_resources, &node_inf);
if (res != B_OK)
goto err;
{
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);
status = dm_allocate_node(attrs, ioResources, &newNode);
if (status != B_OK) {
// always "consume" I/O resources
dm_release_io_resources(ioResources);
return status;
}
// check whether this device already existed and thus is redetected
res = is_device_redetected(node_inf, parent, &redetected);
if (res != B_OK)
goto err1;
if (pnp_get_attr_string(newNode, B_DRIVER_MODULE, &driverName, false) != B_OK)
status = B_BAD_VALUE;
if (redetected) {
// upon redetect, resources are released instead of transferred and
// no node is returned
*node = NULL;
res = B_OK;
goto err1;
TRACE(("dm_register_node(driver = %s)\n", driverName));
free(driverName);
if (status != B_OK) {
dprintf("device_manager: Missing driver module name.\n");
goto err;
}
// transfer resources to device, unregistering all colliding devices;
// this cannot fail - we've already allocated the resource handle array
pnp_assign_io_resources(node_inf, io_resources);
pnp_create_node_links(node_inf, parent);
dm_assign_io_resources(newNode, ioResources);
// make it public
res = mark_node_registered(node_inf);
if (res != B_OK)
goto err2;
dm_add_child_node(parent, newNode);
// 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 (pnp_postpone_probing(node_inf)) {
// return without decrementing ref_count - else node may get
// lost before deferred probe
*node = node_inf;
return B_OK;
if (parent == NULL || parent->registered) {
// register all device nodes not yet registered - build a list
// that contain all of them, and then empty it one by one (during
// iteration, there might be new nodes added)
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 (res != B_OK)
goto err2;
if (_node)
*_node = newNode;
pnp_load_driver_automatically(node_inf, false);
*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;
return B_OK;
err2:
// use this exit after i/o resources have been transferred to node
pnp_remove_node_ref(node_inf);
return res;
err1:
// alloc_node has set ref_count to one for safety, correct this now
pnp_remove_node_ref(node_inf);
{
// nodes popped from the stack also need their reference count released
device_node_info *node;
while ((node = pop_node_from_stack(&stack)) != NULL) {
dm_put_node(node);
}
}
err:
// always "consume" i/o resources
pnp_release_io_resources(io_resources);
return res;
// this also releases the I/O resources
dm_put_node(newNode);
return status;
}
// public: unregister device node
/** Unregister device node.
* This also makes sure that all children of this node are unregistered.
*/
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));
if (node == NULL)
return B_OK;
// unregistered node and all children
// unregistered node and all children
benaphore_lock(&gNodeLock);
pnp_unregister_node_rec(node, &dependency_list);
if (node->parent != NULL)
list_remove_item(&node->parent->children, node);
benaphore_unlock(&gNodeLock);
pnp_unload_driver_automatically(node, false);
// tell driver about their unregistration
dm_notify_unregistration(node);
// tell drivers about their unregistration
pnp_notify_unregistration(dependency_list);
// unregister children recursively
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
pnp_unref_unregistered_nodes(dependency_list);
dm_put_node(node);
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
#define PNP_ROOT_TYPE_NAME "pnp/root"
// 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;
#define PNP_ROOT_MODULE_NAME "system/devices_root/driver_v1"
void
pnp_root_init_root(void)
dm_init_root_node(void)
{
device_attr attrs[] = {
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_ROOT_TYPE_NAME }},
// 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_MODULE, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
{ B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "Devices Root" }},
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "root" }},
{ NULL }
};
if (pnp_register_device(NULL, attrs, NULL, &sRootNode) != B_OK)
dprintf("Cannot register PnP-Root\n");
// ToDo: don't panic for now
// 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);
if (dm_register_node(NULL, attrs, NULL, &gRootNode) != B_OK) {
// ToDo: don't panic for now
dprintf("Cannot register Devices Root Node\n");
}
}
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;
}
static status_t
pnp_root_uninit_device(void *cookie)
root_uninit_driver(void *cookie)
{
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
std_ops(int32 op, ...)
root_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
@@ -193,12 +83,13 @@ driver_module_info gDeviceRootModule = {
{
PNP_ROOT_MODULE_NAME,
0,
std_ops,
root_std_ops,
},
pnp_root_init_device,
pnp_root_uninit_device,
NULL,
NULL, // supported devices
NULL, // register device
root_init_driver,
root_uninit_driver,
NULL,
NULL
};
+140 -350
View File
@@ -21,7 +21,9 @@
#include "device_manager_private.h"
#include <KernelExport.h>
#include <string.h>
#include <stdlib.h>
#define TRACE_SCAN
@@ -31,284 +33,68 @@
# define TRACE(x) ;
#endif
static status_t scan(device_node_info *node, bool rescan);
/** public function: rescan PnP node */
status_t
pnp_rescan(device_node_info *node, uint32 depth)
static int32 sRescanning = 0;
#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
pnp_initial_scan(device_node_info *node)
void
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);
for (child = node->children; child != NULL; child = next_child) {
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);
}
pnp_probe_waiting_children_nolock(node);
benaphore_unlock(&gNodeLock);
}
/** 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;
}
#endif
/** ask bus to (re-)scan for connected devices */
static void
rescan_bus(device_node_info *node)
scan_bus(device_node_info *node, bool rescan)
{
// busses can register their children themselves
bus_module_info *interface;
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
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)
pnp_start_hook_call(node);
if (interface->rescan != NULL)
interface->rescan(cookie);
if (rescan) {
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_unload_driver(node);
// time to execute delayed probing
if (defer_probe)
pnp_probe_waiting_children(node);
// pnp_probe_waiting_children(node);
}
/** rescan for consumers
* ignore_fixed_consumers - true, to leave fixed consumers alone
/** recursively scan children of node (using depth-scan).
* node_lock must be hold
*/
status_t
pnp_rescan_int(device_node_info *node, uint32 depth,
bool ignore_fixed_consumers)
static status_t
recursive_scan(device_node_info *node)
{
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;
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();
// 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);
isBus = pnp_get_attr_uint8(node, PNP_BUS_IS_BUS, &dummy, false) == B_OK;
// do the real thing - scan node
if (is_bus)
rescan_bus(node);
if (!rescan) {
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 (!ignore_fixed_consumers) {
TRACE(("scan fixed consumers\n"));
if (isBus)
scan_bus(node, false);
res = pnp_notify_fixed_consumers(node);
if (res != B_OK)
goto err;
// ask possible children to register their nodes
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);
// mark scan as being finished to not block recursive scans
node->rescan_depth = 0;
// scan children recursively;
// keep the node_lock to make sure noone removes children meanwhile
if (depth > 1)
res = recursive_scan(node, depth);
if (rescan && isBus)
status = recursive_scan(node);
pnp_remove_node_ref_nolock(node);
benaphore_unlock(&gNodeLock);
//pnp_unload_boot_links();
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;
TRACE(("scan(): done (%p) - %s\n", node, strerror(status)));
return status;
}
// #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
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))
return B_BAD_VALUE;
v->dir_next = dir->stream.u.dir.dir_head;
dir->stream.u.dir.dir_head = v;
vnode->dir_next = dir->stream.u.dir.dir_head;
dir->stream.u.dir.dir_head = vnode;
v->parent = dir;
vnode->parent = dir;
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;
}
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 *last_v;
struct devfs_vnode *vnode = dir->stream.u.dir.dir_head;
struct devfs_vnode *lastNode = NULL;
for (v = dir->stream.u.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) {
if (v == findit) {
/* make sure all dircookies dont point to this vnode */
update_dircookies(dir, v);
for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) {
if (vnode == removeNode) {
// make sure no dircookies point to this vnode
update_dircookies(dir, vnode);
if (last_v)
last_v->dir_next = v->dir_next;
if (lastNode)
lastNode->dir_next = vnode->dir_next;
else
dir->stream.u.dir.dir_head = v->dir_next;
v->dir_next = NULL;
dir->stream.u.dir.dir_head = vnode->dir_next;
vnode->dir_next = 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;
}
}
@@ -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));
if (*_vnode)
return 0;
return B_OK;
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);
notify_listener(B_STAT_CHANGED, fs->id, 0, 0, vnode->id, NULL);
notify_stat_changed(fs->id, vnode->id, statMask);
return B_OK;
}
@@ -1626,15 +1633,11 @@ file_system_info gDeviceFileSystem = {
// 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[] =
{
{ 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" }},
static const device_attr pnp_devfs_attrs[] = {
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ NULL }
};
@@ -1644,20 +1647,13 @@ static const device_attr pnp_devfs_attrs[] =
static status_t
pnp_devfs_register_device(device_node_handle parent)
{
char *str = NULL, *filename = NULL;
char *filename = NULL;
device_node_handle node;
status_t status;
TRACE(("pnp_devfs_probe()\n"));
// make sure we can handle this parent
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) {
if (sDeviceManager->get_attr_string(parent, PNP_DEVFS_FILENAME, &filename, true) != B_OK) {
dprintf("devfs: Item containing file name is missing\n");
status = B_ERROR;
goto err1;
@@ -1665,13 +1661,16 @@ pnp_devfs_register_device(device_node_handle parent)
TRACE(("Adding %s\n", filename));
pnp_devfs_driver_info *info;
status = pnp->load_driver(parent, NULL, (driver_module_info **)&info, NULL);
if (status != B_OK)
status = sDeviceManager->register_device(parent, pnp_devfs_attrs, NULL, &node);
if (status != B_OK || node == NULL)
goto err1;
status = pnp->register_device(parent, pnp_devfs_attrs, NULL, &node);
if (status != B_OK || node == NULL)
// ToDo: this is a hack to get things working (init_driver() only works for registered nodes)
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;
//add_device(device);
@@ -1683,11 +1682,10 @@ pnp_devfs_register_device(device_node_handle parent)
return B_OK;
err3:
pnp->unregister_device(node);
sDeviceManager->uninit_driver(parent);
err2:
pnp->unload_driver(parent);
sDeviceManager->unregister_device(node);
err1:
free(str);
free(filename);
return status;
@@ -1728,9 +1726,9 @@ pnp_devfs_device_removed(device_node_handle node, void *cookie)
#endif
TRACE(("pnp_devfs_device_removed()\n"));
#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!
ACQUIRE_BEN( &device_list_lock );
@@ -1738,9 +1736,9 @@ pnp_devfs_device_removed(device_node_handle node, void *cookie)
if( device->parent == parent )
break;
}
if( device != NULL ) {
pnp_devfs_remove_device( device );
pnp_devfs_remove_device(device);
} else {
SHOW_ERROR( 0, "bug: node %p couldn't been found", node );
res = B_NAME_NOT_FOUND;
@@ -1758,10 +1756,10 @@ pnp_devfs_std_ops(int32 op, ...)
{
switch (op) {
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:
put_module(DEVICE_MANAGER_MODULE_NAME);
put_module(B_DEVICE_MANAGER_MODULE_NAME);
return B_OK;
default:
@@ -1777,10 +1775,13 @@ driver_module_info gDeviceForDriversModule = {
pnp_devfs_std_ops
},
NULL,
NULL,
NULL, // supports device
pnp_devfs_register_device,
pnp_devfs_device_removed
NULL, // init driver
NULL, // uninit driver
pnp_devfs_device_removed,
NULL, // cleanup
NULL, // get paths
};