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:
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PCI bus manager
|
PCI bus manager
|
||||||
@@ -11,10 +11,9 @@
|
|||||||
#define _PCI2_H
|
#define _PCI2_H
|
||||||
|
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
//#include "r5_wrapper.h"
|
|
||||||
#include <PCI.h>
|
#include <PCI.h>
|
||||||
|
|
||||||
// currently, this structure is disables to avoid collision with R5 header
|
// currently, this structure is disabled to avoid collision with R5 header
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
typedef struct pci_info {
|
typedef struct pci_info {
|
||||||
@@ -89,26 +88,22 @@ typedef struct pci_device_info *pci_device;
|
|||||||
typedef struct pci_device_module_info {
|
typedef struct pci_device_module_info {
|
||||||
driver_module_info info;
|
driver_module_info info;
|
||||||
|
|
||||||
uint8 (*read_io_8) (pci_device device, int mapped_io_addr);
|
uint8 (*read_io_8)(pci_device device, int mapped_io_addr);
|
||||||
void (*write_io_8) (pci_device device, int mapped_io_addr, uint8 value);
|
void (*write_io_8)(pci_device device, int mapped_io_addr, uint8 value);
|
||||||
uint16 (*read_io_16) (pci_device device, int mapped_io_addr);
|
uint16 (*read_io_16)(pci_device device, int mapped_io_addr);
|
||||||
void (*write_io_16) (pci_device device, int mapped_io_addr, uint16 value);
|
void (*write_io_16)(pci_device device, int mapped_io_addr, uint16 value);
|
||||||
uint32 (*read_io_32) (pci_device device, int mapped_io_addr);
|
uint32 (*read_io_32)(pci_device device, int mapped_io_addr);
|
||||||
void (*write_io_32) (pci_device device, int mapped_io_addr, uint32 value);
|
void (*write_io_32)(pci_device device, int mapped_io_addr, uint32 value);
|
||||||
|
|
||||||
uint32 (*read_pci_config) (
|
uint32 (*read_pci_config)(pci_device device,
|
||||||
pci_device device,
|
|
||||||
uchar offset, /* offset in configuration space */
|
uchar offset, /* offset in configuration space */
|
||||||
uchar size /* # bytes to read (1, 2 or 4) */
|
uchar size); /* # bytes to read (1, 2 or 4) */
|
||||||
);
|
void (*write_pci_config)(pci_device device,
|
||||||
void (*write_pci_config) (
|
|
||||||
pci_device device,
|
|
||||||
uchar offset, /* offset in configuration space */
|
uchar offset, /* offset in configuration space */
|
||||||
uchar size, /* # bytes to write (1, 2 or 4) */
|
uchar size, /* # bytes to write (1, 2 or 4) */
|
||||||
uint32 value /* value to write */
|
uint32 value); /* value to write */
|
||||||
);
|
|
||||||
|
|
||||||
void * (*ram_address) (pci_device device, const void *physical_address_in_system_memory);
|
void *(*ram_address)(pci_device device, const void *physical_address_in_system_memory);
|
||||||
|
|
||||||
/* status_t (*allocate_iomem)( void *base, size_t len, const char *name );
|
/* status_t (*allocate_iomem)( void *base, size_t len, const char *name );
|
||||||
status_t (*release_iomem)( void *base, size_t len );
|
status_t (*release_iomem)( void *base, size_t len );
|
||||||
@@ -118,8 +113,6 @@ typedef struct pci_device_module_info {
|
|||||||
} pci_device_module_info;
|
} pci_device_module_info;
|
||||||
|
|
||||||
|
|
||||||
// type of PCI device
|
|
||||||
#define PCI_DEVICE_TYPE_NAME "pci/device/v1"
|
|
||||||
// directory of PCI drivers
|
// directory of PCI drivers
|
||||||
#define PCI_DRIVERS_DIR "pci"
|
#define PCI_DRIVERS_DIR "pci"
|
||||||
|
|
||||||
|
|||||||
@@ -2,136 +2,10 @@
|
|||||||
* Copyright 2004-2005, Haiku Inc. All Rights Reserved.
|
* Copyright 2004-2005, Haiku Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT license.
|
* Distributed under the terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (c) 2003-04, Thomas Kurschel
|
|
||||||
|
|
||||||
PnP manager; Takes care of registration and loading of PnP drivers
|
|
||||||
|
|
||||||
Read pnp_driver.h first to understand the basic idea behind PnP drivers.
|
|
||||||
|
|
||||||
To register a driver node, use register_driver. If the device got lost,
|
|
||||||
use unregister_driver (note: if the parent node is removed, your node
|
|
||||||
get removed automatically as your driver has obviously nothing to work
|
|
||||||
with anymore). To get access to a (parent) device, use load_driver/
|
|
||||||
unload_driver.
|
|
||||||
|
|
||||||
To let the manager find a consumer (see pnp_driver.h), you can either
|
|
||||||
specify its name directly during registration, using a
|
|
||||||
PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the
|
|
||||||
appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute.
|
|
||||||
|
|
||||||
Searching of dynamic consumers is done as follows:
|
|
||||||
|
|
||||||
- First, the manager searches for a Specific driver in the base
|
|
||||||
directory (see below)
|
|
||||||
- If no Specific driver is found, all Generic drivers stored under
|
|
||||||
"generic" sub-directory are informed in turn until one returns success
|
|
||||||
- Finally, _all_ Universal drivers, stored in the "universal" sub-
|
|
||||||
directory, are informed
|
|
||||||
|
|
||||||
Specification of the base directory and of the names of Specific
|
|
||||||
drivers is done via a file name pattern given by a
|
|
||||||
PNP_DRIVER_DYNAMIC_CONSUMER attribute.
|
|
||||||
|
|
||||||
First, all substrings of the form "%attribute_name%" are replaced by the
|
|
||||||
content of the attribute "attribute_name" as follows:
|
|
||||||
|
|
||||||
- if the attribute contains an integer value, its content is converted to hex
|
|
||||||
(lowercase) with a fixed length according to the attribute's value range
|
|
||||||
- the content of string attributes is quoted by " and invalid characters
|
|
||||||
(i.e. /%" and all characters outside 32..126) are replaced by their
|
|
||||||
unsigned decimal value, delimited by %
|
|
||||||
- other attribute types cannot be used
|
|
||||||
|
|
||||||
Second, the resulting name is split into chunks according to the presence
|
|
||||||
of | characters (you can escape % and | with a ^ character). These
|
|
||||||
characters are only delimiters and get removed before further processing.
|
|
||||||
The directory before the first | character is the base directory (see
|
|
||||||
above). It contains the "generic" and the "universal" subdirectories.
|
|
||||||
The names of the specific drivers are created by first taking the entire
|
|
||||||
file name, then by removing the last chunk, then by removing the last
|
|
||||||
two chunks and so on until only the first chunk is left.
|
|
||||||
|
|
||||||
As drivers can contain multiple modules, the module name is constructed
|
|
||||||
by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file
|
|
||||||
name, seperated by a slash character (note: this only applies to dynamic
|
|
||||||
consumers; for fixed consumers, you specify the module name directly via
|
|
||||||
PNP_DRIVER_FIXED_CONSUMER).
|
|
||||||
|
|
||||||
E.g. given a dynamic consumer pattern of
|
|
||||||
"pci/vendor=%vendor_id%|, device=%device_id%" for a device with the
|
|
||||||
attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the
|
|
||||||
PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and
|
|
||||||
(if the first one fails/doesn't exist) "pci/vendor=0123". If they both
|
|
||||||
refuse to handle the device, all drivers under "pci/generic" are tried
|
|
||||||
until one accepts the device. Finally, all drivers under "pci/universal"
|
|
||||||
are loaded, whatever happened before.
|
|
||||||
|
|
||||||
In practise, you should try to use specific drivers as much as possible.
|
|
||||||
If detection based on device IDs is impossible (e.g. because the bus
|
|
||||||
doesn't support them at all), you can put the driver under "generic".
|
|
||||||
Generic drivers can also be used to specify wrappers that try to load old-
|
|
||||||
style drivers if no new driver can be found. Also, they can be used to
|
|
||||||
report an error or invoke an user program that tries downloading a
|
|
||||||
proper Specific driver. Universal drivers are mainly used for
|
|
||||||
informational purposes, e.g. to publish data about each found device,
|
|
||||||
or to provide raw access to all devices.
|
|
||||||
|
|
||||||
If the device uses physical address space or I/O space or ISA DMA
|
|
||||||
channels (called I/O resources), the driver has to acquire these
|
|
||||||
resources. During hardware detection (usually via probe()),
|
|
||||||
acquire_io_resources() must be called to get exclusive access.
|
|
||||||
If no hardware could be found, they must be released via
|
|
||||||
release_io_resources(). If detection was successful, the list of
|
|
||||||
the (acquired) resources must be passed to register_device().
|
|
||||||
Resources can either belong to one hardware detection or to a device.
|
|
||||||
If a hardware detection collides with another, it has to wait;
|
|
||||||
if it collides with a device whose driver is not loaded, the
|
|
||||||
driver loading is blocked. When detection fails, i.e. if
|
|
||||||
release_io_resources() is called, all blocked drivers can be loaded
|
|
||||||
again. If the detection fails, i.e. the resources are transferred
|
|
||||||
via register_device(), all blocked devices are unregistered and
|
|
||||||
pending load requests aborted. If a hardware detection collides
|
|
||||||
with a device whose driver is loaded, acquire_io_resources() fails
|
|
||||||
with B_BUSY. As this makes a hardware rescan impossible if the
|
|
||||||
driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN
|
|
||||||
for nodes that use I/O resources (see below).
|
|
||||||
|
|
||||||
To search for new drivers for a given device node, use rescan(). This
|
|
||||||
marks all consumer devices as being verified and calls probe()
|
|
||||||
of all consumers drivers (see above) to let them rescan the parent
|
|
||||||
for devices. The <depth> parameter determines the nesting level, e.g.
|
|
||||||
2 means that first the consumers are scanned and then the consumers
|
|
||||||
of the consumers.
|
|
||||||
|
|
||||||
Normally, all devices can be rescanned. If a driver cannot handle
|
|
||||||
a rescan safely when it is loaded (i.e. used by a consumer), it
|
|
||||||
must set PNP_DRIVER_NO_LIVE_RESCAN, in which case the device is
|
|
||||||
ignored during rescan if the driver is loaded and attempts
|
|
||||||
to load the driver during a rescan are blocked until the rescan
|
|
||||||
is finished. If rescanning a device is not possible at all, it must
|
|
||||||
have set PNP_DRIVER_NEVER_RESCAN to always ignore it.
|
|
||||||
|
|
||||||
To distinguish between new devices, lost devices and redetected
|
|
||||||
devices, consumer devices should provide a connection code and a
|
|
||||||
device identifier. They are specified by PNP_DRIVER_CONNECTION and
|
|
||||||
PNP_DRIVER_CONNECTION respectively, and are expanded in the same way
|
|
||||||
as PNP_DRIVER_DYNAMIC_CONSUMER. It is assumed that there can be only
|
|
||||||
one device per connection and that a device can be uniquely identify
|
|
||||||
by a device identifier. If a consumer device is registered on the
|
|
||||||
same connection as an existing device but with a different device
|
|
||||||
identifier, the old device gets unregistered automatically. If both
|
|
||||||
connection and device identifier are the same, registration is
|
|
||||||
handled as a redetection and ignored (unless a different type or
|
|
||||||
driver module is specified - in this case, the device is replaced).
|
|
||||||
Devices that were not redetected during a rescan get unregistered
|
|
||||||
unless they were ignored (see above).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _DEVICE_MANAGER_H
|
#ifndef _DEVICE_MANAGER_H
|
||||||
#define _DEVICE_MANAGER_H
|
#define _DEVICE_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
#include <TypeConstants.h>
|
#include <TypeConstants.h>
|
||||||
#include <Drivers.h>
|
#include <Drivers.h>
|
||||||
#include <module.h>
|
#include <module.h>
|
||||||
@@ -155,7 +29,7 @@ typedef struct {
|
|||||||
// I/O port: first port address (16 bit)
|
// I/O port: first port address (16 bit)
|
||||||
// ISA DMA channel: channel number (0-7)
|
// ISA DMA channel: channel number (0-7)
|
||||||
|
|
||||||
uint32 len;
|
uint32 length;
|
||||||
// I/O memory: size of address range (32 bit)
|
// I/O memory: size of address range (32 bit)
|
||||||
// I/O port: size of port range (16 bit)
|
// I/O port: size of port range (16 bit)
|
||||||
// ISA DMA channel: must be 1
|
// ISA DMA channel: must be 1
|
||||||
@@ -173,98 +47,48 @@ typedef struct {
|
|||||||
const char *string; // B_STRING_TYPE
|
const char *string; // B_STRING_TYPE
|
||||||
struct { // B_RAW_TYPE
|
struct { // B_RAW_TYPE
|
||||||
void *data;
|
void *data;
|
||||||
size_t len;
|
size_t length;
|
||||||
} raw;
|
} raw;
|
||||||
} value;
|
} value;
|
||||||
} device_attr;
|
} device_attr;
|
||||||
|
|
||||||
|
|
||||||
// handle of device node
|
|
||||||
typedef struct device_node_info *device_node_handle;
|
typedef struct device_node_info *device_node_handle;
|
||||||
|
|
||||||
// handle of acquired I/O resource
|
|
||||||
typedef struct io_resource_info *io_resource_handle;
|
typedef struct io_resource_info *io_resource_handle;
|
||||||
|
|
||||||
// handle of node attribute
|
|
||||||
typedef struct device_attr_info *device_attr_handle;
|
typedef struct device_attr_info *device_attr_handle;
|
||||||
|
|
||||||
|
|
||||||
typedef struct driver_module_info driver_module_info;
|
typedef struct driver_module_info driver_module_info;
|
||||||
|
|
||||||
// interface of PnP manager
|
|
||||||
|
// interface of the device manager
|
||||||
|
|
||||||
typedef struct device_manager_info {
|
typedef struct device_manager_info {
|
||||||
module_info info;
|
module_info info;
|
||||||
|
|
||||||
// load driver
|
status_t (*init_driver)(device_node_handle node, void *userCookie,
|
||||||
// node - node whos driver is to be loaded
|
|
||||||
// user_cookie - cookie to be passed to init_device of driver
|
|
||||||
// interface - interface of loaded driver
|
|
||||||
// cookie - device cookie issued by loaded driver
|
|
||||||
status_t (*load_driver)(device_node_handle node, void *userCookie,
|
|
||||||
driver_module_info **interface, void **cookie);
|
driver_module_info **interface, void **cookie);
|
||||||
// unload driver
|
status_t (*uninit_driver)(device_node_handle node);
|
||||||
status_t (*unload_driver)(device_node_handle node);
|
|
||||||
|
|
||||||
// rescan node for new dynamic drivers
|
status_t (*rescan)(device_node_handle node);
|
||||||
// node - node whose dynamic drivers are to be scanned
|
|
||||||
// depth - recursive depth (>= 1)
|
|
||||||
status_t (*rescan)(device_node_handle node, uint32 depth);
|
|
||||||
|
|
||||||
// register device
|
|
||||||
// parent - parent node
|
|
||||||
// attributes - NULL-terminated array of node attributes
|
|
||||||
// io_resources - NULL-terminated array of I/O resources (can be NULL)
|
|
||||||
// node - new node handle
|
|
||||||
// on return, io_resources are invalid: on success I/O resources belong
|
|
||||||
// to node, on fail they are released;
|
|
||||||
// if device is already registered, B_OK is returned but *node is NULL
|
|
||||||
status_t (*register_device)(device_node_handle parent,
|
status_t (*register_device)(device_node_handle parent,
|
||||||
const device_attr *attrs,
|
const device_attr *attrs,
|
||||||
const io_resource_handle *io_resources,
|
const io_resource_handle *io_resources,
|
||||||
device_node_handle *node);
|
device_node_handle *node);
|
||||||
// unregister device
|
|
||||||
// all nodes having this node as their parent are unregistered too.
|
|
||||||
// if the node contains PNP_MANAGER_ID_GENERATOR/PNP_MANAGER_AUTO_ID
|
|
||||||
// pairs, the id specified this way is freed too
|
|
||||||
status_t (*unregister_device)(device_node_handle node);
|
status_t (*unregister_device)(device_node_handle node);
|
||||||
|
|
||||||
// acquire I/O resources
|
status_t (*get_next_child_device)(device_node_handle parent,
|
||||||
// resources - NULL-terminated array of resources to acquire
|
device_node_handle *_node, const device_attr *attrs);
|
||||||
// handles - NULL-terminated array of handles (one per resource);
|
device_node_handle (*get_parent)(device_node_handle node);
|
||||||
// array must be provided by caller
|
void (*put_device_node)(device_node_handle node);
|
||||||
// return B_BUSY if a resource is used by a loaded driver
|
|
||||||
status_t (*acquire_io_resources)(io_resource *resources,
|
status_t (*acquire_io_resources)(io_resource *resources,
|
||||||
io_resource_handle *handles);
|
io_resource_handle *handles);
|
||||||
// release I/O resources
|
|
||||||
// handles - NULL-terminated array of handles
|
|
||||||
status_t (*release_io_resources)(const io_resource_handle *handles);
|
status_t (*release_io_resources)(const io_resource_handle *handles);
|
||||||
|
|
||||||
// find device by node content
|
|
||||||
// the given attributes must _uniquely_ identify a device node;
|
|
||||||
// parent - parent node (-1 for don't-care)
|
|
||||||
// attrs - list of attributes (can be NULL)
|
|
||||||
// return: NULL if no device or multiple(!) devices found
|
|
||||||
device_node_handle (*find_device)(device_node_handle parent,
|
|
||||||
const device_attr *attrs);
|
|
||||||
|
|
||||||
// create unique id
|
|
||||||
// generator - name of id set
|
|
||||||
// if result >= 0 - unique id
|
|
||||||
// result < 0 - error code
|
|
||||||
int32 (*create_id)(const char *generator);
|
int32 (*create_id)(const char *generator);
|
||||||
// free unique id
|
|
||||||
status_t (*free_id)(const char *generator, uint32 id);
|
status_t (*free_id)(const char *generator, uint32 id);
|
||||||
|
|
||||||
// get parent device node
|
|
||||||
device_node_handle (*get_parent)(device_node_handle node);
|
|
||||||
|
|
||||||
// helpers to extract attribute by name.
|
|
||||||
// if <recursive> is true, parent nodes are scanned if
|
|
||||||
// attribute isn't found in current node; unless you declared
|
|
||||||
// the attribute yourself, use recursive search to handle
|
|
||||||
// intermittent nodes, e.g. defined by filter drivers, transparently.
|
|
||||||
// for raw and string attributes, you get a copy that must
|
|
||||||
// be freed by caller
|
|
||||||
status_t (*get_attr_uint8)(device_node_handle node,
|
status_t (*get_attr_uint8)(device_node_handle node,
|
||||||
const char *name, uint8 *value, bool recursive);
|
const char *name, uint8 *value, bool recursive);
|
||||||
status_t (*get_attr_uint16)(device_node_handle node,
|
status_t (*get_attr_uint16)(device_node_handle node,
|
||||||
@@ -279,272 +103,95 @@ typedef struct device_manager_info {
|
|||||||
const char *name, void **data, size_t *_size,
|
const char *name, void **data, size_t *_size,
|
||||||
bool recursive);
|
bool recursive);
|
||||||
|
|
||||||
// get next attribute of node;
|
|
||||||
// on call, *<attr_handle> must contain handle of an attribute;
|
|
||||||
// on return, *<attr_handle> is replaced by the next attribute or
|
|
||||||
// NULL if it was the last;
|
|
||||||
// to get the first attribute, <attr_handle> must point to NULL;
|
|
||||||
// the returned handle must be released by either passing it to
|
|
||||||
// another get_next_attr() call or by using release_attr()
|
|
||||||
// directly
|
|
||||||
status_t (*get_next_attr)(device_node_handle node,
|
status_t (*get_next_attr)(device_node_handle node,
|
||||||
device_attr_handle *attrHandle);
|
device_attr_handle *attrHandle);
|
||||||
|
|
||||||
// release attribute handle <attr_handle> of <node>;
|
|
||||||
// see get_next_attr
|
|
||||||
status_t (*release_attr)(device_node_handle node,
|
status_t (*release_attr)(device_node_handle node,
|
||||||
device_attr_handle attr_handle);
|
device_attr_handle attr_handle);
|
||||||
|
|
||||||
// retrieve attribute data with handle given;
|
|
||||||
// <attr> is only valid as long as you don't release <attr_handle>
|
|
||||||
// implicitely or explicitely
|
|
||||||
status_t (*retrieve_attr)(device_attr_handle attr_handle,
|
status_t (*retrieve_attr)(device_attr_handle attr_handle,
|
||||||
const device_attr **attr);
|
const device_attr **attr);
|
||||||
|
|
||||||
// change/add attribute <attr> of/to node
|
|
||||||
status_t (*write_attr)(device_node_handle node,
|
status_t (*write_attr)(device_node_handle node,
|
||||||
const device_attr *attr);
|
const device_attr *attr);
|
||||||
|
|
||||||
// remove attribute of node by name
|
|
||||||
// <name> is name of attribute
|
|
||||||
status_t (*remove_attr)(device_node_handle node, const char *name);
|
status_t (*remove_attr)(device_node_handle node, const char *name);
|
||||||
} device_manager_info;
|
} device_manager_info;
|
||||||
|
|
||||||
|
|
||||||
// standard attributes:
|
#define B_DEVICE_MANAGER_MODULE_NAME "system/device_manager/v1"
|
||||||
|
|
||||||
// if you are using an id generator (see create_id), you can let the
|
|
||||||
// manager automatically free the id when the node is deleted by setting
|
|
||||||
// the following attributes:
|
|
||||||
// name of generator (string)
|
|
||||||
#define PNP_MANAGER_ID_GENERATOR "id_generator"
|
|
||||||
// generated id (uint32)
|
|
||||||
#define PNP_MANAGER_AUTO_ID "auto_id"
|
|
||||||
|
|
||||||
// modulename of PnP manager
|
|
||||||
#define DEVICE_MANAGER_MODULE_NAME "sys/device_manager/v1"
|
|
||||||
|
|
||||||
|
|
||||||
// former pnp_driver.h
|
|
||||||
/*
|
|
||||||
Copyright (c) 2003-04, Thomas Kurschel
|
|
||||||
|
|
||||||
Required interface of PnP drivers
|
|
||||||
|
|
||||||
In contrast to standard BeOS drivers, PnP drivers are normal modules
|
|
||||||
having the interface described below.
|
|
||||||
|
|
||||||
Every device is described by its driver via a PnP node with properties
|
|
||||||
described in PnP Node Attributes. Devices are organized in a hierarchy,
|
|
||||||
e.g. a devfs device is a hard disk device that is connected to a
|
|
||||||
controller, which is a PCI device, that is connected to a PCI bus.
|
|
||||||
Every device is connected to its lower-level device via a parent link
|
|
||||||
stored in its Node. The higher-level is called the consumer of the
|
|
||||||
lower-level device. If the lower-level device gets removed, all its
|
|
||||||
consumers are removed too.
|
|
||||||
|
|
||||||
In our example, the hierarchy is
|
|
||||||
|
|
||||||
devfs device -> hard disk -> controller -> PCI device -> PCI bus
|
|
||||||
|
|
||||||
If the PCI bus is removed, everything up to including the devfs device
|
|
||||||
is removed too.
|
|
||||||
|
|
||||||
The driver hierarchy is constructed bottom-up, i.e. the lower-level
|
|
||||||
driver searches for a corresponding consumer, which in turns searches
|
|
||||||
for its consumer and so on. The lowest driver is usually something like
|
|
||||||
a PCI bus, the highest driver is normally a devfs entry (see pnp_devfs.h).
|
|
||||||
Registration of devices and the search for appropriate consumers is
|
|
||||||
done via the pnp_manager (see pnp_manager.h).
|
|
||||||
|
|
||||||
When a potential consumer is found, it gets informed about the new
|
|
||||||
lower-level device and can either refuse its handling or accept it.
|
|
||||||
On accept, it has to create a new node with the lower-level device
|
|
||||||
node as its parent.
|
|
||||||
|
|
||||||
Loading of drivers is done on demand, i.e. if the consumer wants to
|
|
||||||
access its lower-level device, it explicitely loads the corresponding
|
|
||||||
driver, and once it doesn't need it anymore, the lower-level driver
|
|
||||||
must be unloaded. Usually, this process happens recursively, i.e. in
|
|
||||||
our example, the hard disk driver loads the controller driver, which
|
|
||||||
loads the PCI device driver which loads the PCI bus driver. The same
|
|
||||||
process applies to unloading.
|
|
||||||
|
|
||||||
Because of this dynamic loading, drivers must store persistent data
|
|
||||||
in the node of their devices. Please be aware that you cannot modify
|
|
||||||
a node once published.
|
|
||||||
|
|
||||||
If a device gets removed, you must unregister its node. As said, the
|
|
||||||
PnP manager will automatically unregister all consumers too. The
|
|
||||||
corresponding drivers are notified to stop talking to their lower-level
|
|
||||||
devices and to terminate running requests. Normally, you want to use a
|
|
||||||
dedicated variable that is verified at each call to make sure that the
|
|
||||||
parent is still there. The notification is done independantly of the
|
|
||||||
driver being loaded by its consumer(s) or not. If it isn't loaded,
|
|
||||||
the notification callback gets NULL as the device cookie; normally, the
|
|
||||||
driver returns immediately in this case. As soon as both the device
|
|
||||||
is removed and the driver is unloaded, device_cleanup gets called to
|
|
||||||
free resources that couldn't be safely removed in device_removed when
|
|
||||||
the driver was still loaded.
|
|
||||||
|
|
||||||
If a device has exactly one consumer, they often interact in some way.
|
|
||||||
To simplify that, the consumer can pass a user-cookie to its parent
|
|
||||||
during load. In this case, it's up to the parent driver to get a
|
|
||||||
pointer to the interface of the consumer. Effectively, such consumers
|
|
||||||
have one interface for their consumers (base on pnp_driver_info), and
|
|
||||||
a another for their parents (with a completely driver-specific
|
|
||||||
structure).
|
|
||||||
|
|
||||||
In terms of synchronization, loading/unloading/remove-notifications
|
|
||||||
are executed synchroniously, i.e. if e.g. a device is to be unloaded
|
|
||||||
but the drive currently handles a remove-notification, the unloading
|
|
||||||
is delayed until the nofication callback returns. If multiple consumers
|
|
||||||
load a driver, the driver gets initialized only once; subsequent load
|
|
||||||
requests increase an internal load count only and return immediately.
|
|
||||||
In turn, unloading only happens once the load count reaches zero.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// interface of device driver
|
// interface of device driver
|
||||||
|
|
||||||
struct driver_module_info {
|
struct driver_module_info {
|
||||||
module_info info;
|
module_info info;
|
||||||
|
|
||||||
status_t (*init_device)(device_node_handle node, void *user_cookie, void **cookie);
|
float (*supports_device)(device_node_handle parent, bool *_noConnection);
|
||||||
// driver is loaded.
|
|
||||||
// node - node of device
|
|
||||||
// user_cookie - cookie passed by loading driver
|
|
||||||
// cookie - cookie issued by this driver
|
|
||||||
|
|
||||||
status_t (*uninit_device)(void *cookie);
|
|
||||||
// driver gets unloaded.
|
|
||||||
|
|
||||||
status_t (*register_device)(device_node_handle parent);
|
status_t (*register_device)(device_node_handle parent);
|
||||||
// parent was added or is rescanned.
|
|
||||||
// check whether this parent is supported and register
|
status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie);
|
||||||
// any consumer device. Dynamic consumers must return
|
status_t (*uninit_driver)(void *cookie);
|
||||||
// B_OK if they support this parent. All other return
|
|
||||||
// values are ignored.
|
|
||||||
|
|
||||||
void (*device_removed)(device_node_handle node, void *cookie);
|
void (*device_removed)(device_node_handle node, void *cookie);
|
||||||
// a device node, registered by this driver, got removed.
|
|
||||||
// if the driver wasn't loaded when this happenes, no (un)init_device
|
|
||||||
// is called and thus <cookie> is NULL;
|
|
||||||
|
|
||||||
void (*device_cleanup)(device_node_handle node);
|
void (*device_cleanup)(device_node_handle node);
|
||||||
// a device node, registered by this driver, got removed and
|
|
||||||
// the driver got unloaded
|
void (*get_supported_paths)(const char ***_busses, const char ***_devices);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// standard attributes:
|
// standard device node attributes
|
||||||
|
|
||||||
// module name of driver (required, string)
|
#define PNP_MANAGER_ID_GENERATOR "id_generator"
|
||||||
#define PNP_DRIVER_DRIVER "driver"
|
// if you are using an id generator (see create_id), you can let the
|
||||||
// type of driver (required, string)
|
// manager automatically free the id when the node is deleted by setting
|
||||||
#define PNP_DRIVER_TYPE "type"
|
// the following attributes:
|
||||||
// module name of fixed consumer - see pnp_manager.h (optional, string)
|
// name of generator (string)
|
||||||
// append "/0", "/1" etc. if there are multiple fixed consumers
|
#define PNP_MANAGER_AUTO_ID "auto_id"
|
||||||
#define PNP_DRIVER_FIXED_CONSUMER "consumer/fixed"
|
// generated id (uint32)
|
||||||
// dynamic consumers pattern - see pnp_manager.h (optional, string)
|
|
||||||
// append "/0", "/1" etc. if there are multiple dynamic consumers
|
#define B_DRIVER_MODULE "driver/module"
|
||||||
#define PNP_DRIVER_DYNAMIC_CONSUMER "consumer/dynamic"
|
#define B_DRIVER_PRETTY_NAME "driver/pretty name"
|
||||||
|
#define B_DRIVER_FIXED_CHILD "driver/fixed child"
|
||||||
|
#define B_DRIVER_MAPPING "driver/mapping"
|
||||||
|
#define B_DRIVER_BUS "driver/bus"
|
||||||
|
#define B_DRIVER_FIND_DEVICES_ON_DEMAND "driver/on demand"
|
||||||
|
#define B_DRIVER_EXPLORE_LAST "driver/explore last"
|
||||||
|
|
||||||
|
#define B_DRIVER_UNIQUE_DEVICE_ID "unique id"
|
||||||
|
#define B_DRIVER_DEVICE_TYPE "device type"
|
||||||
|
|
||||||
|
#define B_AUDIO_DRIVER_TYPE "audio"
|
||||||
|
#define B_BUS_DRIVER_TYPE "bus"
|
||||||
|
#define B_DISK_DRIVER_TYPE "disk"
|
||||||
|
#define B_GRAPHICS_DRIVER_TYPE "graphics"
|
||||||
|
#define B_INPUT_DRIVER_TYPE "input"
|
||||||
|
#define B_MISC_DRIVER_TYPE "misc"
|
||||||
|
#define B_NETWORK_DRIVER_TYPE "net"
|
||||||
|
#define B_VIDEO_DRIVER_TYPE "video"
|
||||||
|
|
||||||
// connection of parent the device is attached to (optional, string)
|
|
||||||
// there can be only one device per connection
|
|
||||||
#define PNP_DRIVER_CONNECTION "connection"
|
#define PNP_DRIVER_CONNECTION "connection"
|
||||||
// pattern device identifier (optional, string)
|
// connection of parent the device is attached to (optional, string)
|
||||||
// it is expanded and used to detect changed devices
|
// there can be only one device per connection
|
||||||
#define PNP_DRIVER_DEVICE_IDENTIFIER "device_identifier"
|
|
||||||
// driver must not be loaded during rescan (optional, uint8)
|
|
||||||
// if != 0, driver must not be loaded during rescan
|
|
||||||
// nor can rescan be started when driver is loaded
|
|
||||||
// if the device uses I/O resources, you _must_ set this
|
|
||||||
// flag as the rescan would always fail if the driver is loaded
|
|
||||||
// due to resource contention
|
|
||||||
#define PNP_DRIVER_NO_LIVE_RESCAN "no_live_rescan"
|
|
||||||
// never rescan this device (optional, uint8)
|
|
||||||
// if != 0, device is never checked during rescan
|
|
||||||
#define PNP_DRIVER_NEVER_RESCAN "never_rescan"
|
|
||||||
// keep driver loaded loaded (optional, uint8)
|
|
||||||
// if != 0, the driver is loaded automatically whenever the node
|
|
||||||
// is registered and unloaded whenever the node is unregistered.
|
|
||||||
// if = 1, driver is temporarily unloaded during rescan
|
|
||||||
// if = 2, driver is not unloaded during rescan
|
|
||||||
// avoid the second case (2) as this makes replacing the driver
|
|
||||||
// impossible without a reboot.
|
|
||||||
#define PNP_DRIVER_ALWAYS_LOADED "always_loaded"
|
|
||||||
|
|
||||||
|
|
||||||
// former pnp_bus.h
|
// interface of a bus device driver
|
||||||
/*
|
|
||||||
Copyright (c) 2003-04, Thomas Kurschel
|
|
||||||
|
|
||||||
Required interface of PnP bus drivers
|
|
||||||
|
|
||||||
Busses consist of two node layers: the lower layer defines the bus,
|
|
||||||
the upper layer defines the abstract devices connected to the bus.
|
|
||||||
Both layers are handled by a bus manager. Actual device nodes are
|
|
||||||
on top of abstract device nodes.
|
|
||||||
|
|
||||||
E.g. if we have a PCI bus with an IDE controller on it, we get
|
|
||||||
|
|
||||||
IDE controller -> PCI device -> PCI bus
|
|
||||||
|
|
||||||
with:
|
|
||||||
IDE controller = actual device node
|
|
||||||
PCI device = abstract device node
|
|
||||||
PCI bus = bus node
|
|
||||||
|
|
||||||
The PCI bus manager establishes both the PCI devices and the PCI busses.
|
|
||||||
|
|
||||||
Abstract device nodes act as a gateway between actual device nodes
|
|
||||||
and the corresponding bus node. They are constructed by the bus
|
|
||||||
node driver via its rescan() hook. To identify a bus node, define
|
|
||||||
PNP_BUS_IS_BUS as an attribute of it. As a result, the PnP manager
|
|
||||||
will call the rescan() method of the bus driver whenever the
|
|
||||||
bus is to be rescanned. Afterwards, all possible dynamic consumers
|
|
||||||
are informed as done for normal nodes.
|
|
||||||
|
|
||||||
Normally, potential device drivers are notified immediately when
|
|
||||||
rescan() registers a new abstract device node. But sometimes, device
|
|
||||||
drivers need to know _all_ devices connected to the bus for correct
|
|
||||||
detection. To ensure this, the bus node must define
|
|
||||||
PNP_BUS_NOTIFY_CONSUMERS_AFTER_RESCAN. In this case, scanning for
|
|
||||||
consumers is postponed until rescan() has finished.
|
|
||||||
|
|
||||||
If hot-plugging of devices can be detected automatically (e.g. USB),
|
|
||||||
you should define PNP_DRIVER_ALWAYS_LOADED, so the bus driver is
|
|
||||||
always loaded and thus capable of handling hot-plug events generated
|
|
||||||
by the bus controller hardware.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// interface of PnP bus
|
|
||||||
typedef struct bus_module_info {
|
typedef struct bus_module_info {
|
||||||
driver_module_info info;
|
driver_module_info info;
|
||||||
|
|
||||||
// (re)scan bus and register all devices.
|
// scan the bus and register all devices.
|
||||||
|
status_t (*register_child_devices)(void *cookie);
|
||||||
|
|
||||||
|
// user initiated rescan of the bus - only propagate changes
|
||||||
|
// you only need to implement this, if you cannot detect device changes yourself
|
||||||
// driver is always loaded during this call, but other hooks may
|
// driver is always loaded during this call, but other hooks may
|
||||||
// be called concurrently
|
// be called concurrently
|
||||||
status_t (*rescan) (void *cookie);
|
status_t (*rescan_bus)(void *cookie);
|
||||||
} bus_module_info;
|
} bus_module_info;
|
||||||
|
|
||||||
|
|
||||||
// standard attributes:
|
// standard attributes
|
||||||
|
|
||||||
// PnP bus identification (required, uint8)
|
// PnP bus identification (required, uint8)
|
||||||
// define this to let the PnP manager know that this is a PnP bus
|
// define this to let the PnP manager know that this is a PnP bus
|
||||||
// the actual content is ignored
|
// the actual content is ignored
|
||||||
#define PNP_BUS_IS_BUS "bus/is_bus"
|
#define PNP_BUS_IS_BUS "bus/is_bus"
|
||||||
|
|
||||||
// defer searching for consumers (optional, uint8)
|
|
||||||
// if != 0, probe() of consumers is called after rescan() of bus
|
|
||||||
// else, probe() of consumers is called during rescan() of bus
|
|
||||||
// normally, consumers are informed about a new device as soon as
|
|
||||||
// it is registered by rescan(), i.e. not all devices may have been
|
|
||||||
// detected and registered yet;
|
|
||||||
// with this flag, detection of consumers is postponed until
|
|
||||||
// rescan() has finished, i.e. when all devices are registered
|
|
||||||
#define PNP_BUS_DEFER_PROBE "bus/defer_probe"
|
|
||||||
|
|
||||||
#endif /* _DEVICE_MANAGER_H */
|
#endif /* _DEVICE_MANAGER_H */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PnP devfs driver interface.
|
PnP devfs driver interface.
|
||||||
@@ -20,9 +20,10 @@
|
|||||||
#ifndef _PNP_DEVFS_H
|
#ifndef _PNP_DEVFS_H
|
||||||
#define _PNP_DEVFS_H
|
#define _PNP_DEVFS_H
|
||||||
|
|
||||||
|
|
||||||
#include <Drivers.h>
|
#include <Drivers.h>
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
//#include "r5_wrapper.h"
|
|
||||||
|
|
||||||
// changed open hook - gets cookie returned by init_device instead of name
|
// changed open hook - gets cookie returned by init_device instead of name
|
||||||
typedef status_t (*pnp_device_open_hook)(void *device_cookie, uint32 flags,
|
typedef status_t (*pnp_device_open_hook)(void *device_cookie, uint32 flags,
|
||||||
@@ -49,9 +50,6 @@ typedef struct pnp_devfs_driver_info {
|
|||||||
// name under which the device should be published under /dev (required, string)
|
// name under which the device should be published under /dev (required, string)
|
||||||
#define PNP_DEVFS_FILENAME "devfs/filename"
|
#define PNP_DEVFS_FILENAME "devfs/filename"
|
||||||
|
|
||||||
// type of devfs device drivers
|
#define PNP_DEVFS_MODULE_NAME "system/devfs/device_v1"
|
||||||
#define PNP_DEVFS_TYPE_NAME "devfs_device"
|
|
||||||
|
|
||||||
#define PNP_DEVFS_MODULE_NAME "sys/pnp_devfs/v1"
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,25 +9,23 @@
|
|||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
|
|
||||||
|
#include <util/list.h>
|
||||||
|
|
||||||
|
|
||||||
typedef struct device_node_info device_node_info;
|
typedef struct device_node_info device_node_info;
|
||||||
|
|
||||||
// info about a device node
|
// info about a device node
|
||||||
struct device_node_info {
|
struct device_node_info {
|
||||||
device_node_info *prev, *next;
|
struct list_link siblings;
|
||||||
device_node_info *siblings_prev, *siblings_next;
|
|
||||||
device_node_info *notify_prev, *notify_next;
|
|
||||||
device_node_info *parent;
|
device_node_info *parent;
|
||||||
device_node_info *children;
|
struct list children;
|
||||||
int32 ref_count; // reference count; see registration.c
|
int32 ref_count;
|
||||||
|
|
||||||
driver_module_info *driver;
|
driver_module_info *driver;
|
||||||
void *cookie;
|
void *cookie;
|
||||||
|
|
||||||
bool registered; // true, if device is officially existent
|
bool registered; // true, if device is officially existent
|
||||||
bool init_finished; // true, if publish_device has been completed
|
|
||||||
// (sync with loader_lock)
|
|
||||||
bool blocked_by_rescan; // true, if device is blocked because of rescan
|
bool blocked_by_rescan; // true, if device is blocked because of rescan
|
||||||
bool verifying; // true, if driver is being verified by rescan
|
|
||||||
bool redetected; // true, if driver was redetected during rescan
|
|
||||||
int32 num_waiting_hooks; // number of waiting hook calls
|
int32 num_waiting_hooks; // number of waiting hook calls
|
||||||
sem_id hook_sem; // sem for waiting hook calls
|
sem_id hook_sem; // sem for waiting hook calls
|
||||||
int32 load_block_count; // load-block nest count
|
int32 load_block_count; // load-block nest count
|
||||||
@@ -39,10 +37,7 @@ struct device_node_info {
|
|||||||
struct device_attr_info *attributes; // list of attributes
|
struct device_attr_info *attributes; // list of attributes
|
||||||
uint32 num_io_resources; // number of I/O resources
|
uint32 num_io_resources; // number of I/O resources
|
||||||
io_resource_handle *io_resources; // array of I/O resource (NULL-terminated)
|
io_resource_handle *io_resources; // array of I/O resource (NULL-terminated)
|
||||||
int32 defer_probing; // > 0 defer probing for consumers of children
|
|
||||||
bool automatically_loaded; // loaded automatically because PNP_DRIVER_ALWAYS_LOADED
|
bool automatically_loaded; // loaded automatically because PNP_DRIVER_ALWAYS_LOADED
|
||||||
device_node_info *unprobed_children; // list of un-probed children
|
|
||||||
device_node_info *unprobed_prev, *unprobed_next; // link for unprobed_children
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,19 +26,14 @@
|
|||||||
static status_t
|
static status_t
|
||||||
ide_channel_added(device_node_handle parent)
|
ide_channel_added(device_node_handle parent)
|
||||||
{
|
{
|
||||||
char *str = NULL, *controller_name = NULL;
|
char *controller_name = NULL;
|
||||||
uint32 channel_id;
|
uint32 channel_id;
|
||||||
|
|
||||||
SHOW_FLOW0(2, "");
|
SHOW_FLOW0(2, "");
|
||||||
|
|
||||||
if (pnp->get_attr_string(parent, PNP_DRIVER_TYPE, &str, false) != B_OK
|
|
||||||
|| strcmp(str, IDE_BUS_TYPE_NAME) != 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
|
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
|
||||||
&controller_name, true) != B_OK) {
|
&controller_name, true) != B_OK) {
|
||||||
pnp->get_attr_string(parent, PNP_DRIVER_DRIVER, &str, false);
|
dprintf("ide: ignored controller - controller name missing\n");
|
||||||
SHOW_ERROR( 0, "Ignored controller managed by %s - controller name missing", str);
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,9 +47,9 @@ ide_channel_added(device_node_handle parent)
|
|||||||
{
|
{
|
||||||
device_attr attrs[] =
|
device_attr attrs[] =
|
||||||
{
|
{
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_SIM_TYPE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
|
|
||||||
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
|
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
|
||||||
{ string: controller_name }},
|
{ string: controller_name }},
|
||||||
// maximum number of blocks per transmission:
|
// maximum number of blocks per transmission:
|
||||||
@@ -81,14 +76,12 @@ ide_channel_added(device_node_handle parent)
|
|||||||
|
|
||||||
res = pnp->register_device(parent, attrs, NULL, &node);
|
res = pnp->register_device(parent, attrs, NULL, &node);
|
||||||
|
|
||||||
free(str);
|
|
||||||
free(controller_name);
|
free(controller_name);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
free(str);
|
|
||||||
free(controller_name);
|
free(controller_name);
|
||||||
|
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@@ -117,9 +110,10 @@ ide_for_controller_interface ide_for_controller_module = {
|
|||||||
&std_ops
|
&std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
NULL,
|
NULL, // supported devices
|
||||||
NULL,
|
|
||||||
ide_channel_added,
|
ide_channel_added,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ scsi_for_sim_interface *scsi;
|
|||||||
fast_log_info *fast_log;
|
fast_log_info *fast_log;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_FAST_LOG
|
||||||
static fast_log_event_type ide_events[] =
|
static fast_log_event_type ide_events[] =
|
||||||
{
|
{
|
||||||
{ ev_ide_send_command, "ev_ide_send_command " },
|
{ ev_ide_send_command, "ev_ide_send_command " },
|
||||||
@@ -64,9 +65,11 @@ static fast_log_event_type ide_events[] =
|
|||||||
{ ev_ide_scan_device_int_found, "ev_ide_scan_device_int_found" },
|
{ ev_ide_scan_device_int_found, "ev_ide_scan_device_int_found" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static void disconnect_worker( ide_bus_info *bus, void *arg );
|
|
||||||
static void set_check_condition( ide_qrequest *qrequest );
|
static void disconnect_worker(ide_bus_info *bus, void *arg);
|
||||||
|
static void set_check_condition(ide_qrequest *qrequest);
|
||||||
|
|
||||||
|
|
||||||
/** check whether this request can be within device */
|
/** check whether this request can be within device */
|
||||||
@@ -541,6 +544,7 @@ finish_all_requests(ide_device_info *device, ide_qrequest *ignore,
|
|||||||
static status_t
|
static status_t
|
||||||
ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
||||||
{
|
{
|
||||||
|
device_node_handle parent;
|
||||||
ide_bus_info *bus;
|
ide_bus_info *bus;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
@@ -566,11 +570,13 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
sprintf(bus->name, "ide_bus %d", (int)channel_id);
|
sprintf(bus->name, "ide_bus %d", (int)channel_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
bus->log = fast_log->start_log(bus->name, ide_events);
|
bus->log = fast_log->start_log(bus->name, ide_events);
|
||||||
if (bus->log == NULL) {
|
if (bus->log == NULL) {
|
||||||
res = B_NO_MEMORY;
|
res = B_NO_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker);
|
init_synced_pc(&bus->scan_bus_syncinfo, scan_device_worker);
|
||||||
init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker);
|
init_synced_pc(&bus->disconnect_syncinfo, disconnect_worker);
|
||||||
@@ -635,9 +641,13 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
bus->can_CQ = false;
|
bus->can_CQ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = pnp->load_driver(pnp->get_parent(node), bus,
|
parent = pnp->get_parent(node);
|
||||||
|
|
||||||
|
res = pnp->init_driver(parent, bus,
|
||||||
(driver_module_info **)&bus->controller,
|
(driver_module_info **)&bus->controller,
|
||||||
(void **)&bus->channel);
|
(void **)&bus->channel);
|
||||||
|
|
||||||
|
pnp->put_device_node(parent);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err5;
|
goto err5;
|
||||||
|
|
||||||
@@ -654,16 +664,15 @@ err4:
|
|||||||
delete_sem(bus->scan_device_sem);
|
delete_sem(bus->scan_device_sem);
|
||||||
err3:
|
err3:
|
||||||
delete_sem(bus->sync_wait_sem);
|
delete_sem(bus->sync_wait_sem);
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
scsi->free_dpc(bus->irq_dpc);
|
scsi->free_dpc(bus->irq_dpc);
|
||||||
|
|
||||||
err1:
|
err1:
|
||||||
uninit_synced_pc(&bus->scan_bus_syncinfo);
|
uninit_synced_pc(&bus->scan_bus_syncinfo);
|
||||||
uninit_synced_pc(&bus->disconnect_syncinfo);
|
uninit_synced_pc(&bus->disconnect_syncinfo);
|
||||||
|
#ifdef USE_FAST_LOG
|
||||||
fast_log->stop_log(bus->log);
|
fast_log->stop_log(bus->log);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
#endif
|
||||||
free(bus);
|
free(bus);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -673,7 +682,10 @@ err:
|
|||||||
static status_t
|
static status_t
|
||||||
ide_sim_uninit_bus(ide_bus_info *bus)
|
ide_sim_uninit_bus(ide_bus_info *bus)
|
||||||
{
|
{
|
||||||
pnp->unload_driver(pnp->get_parent(bus->node));
|
device_node_handle parent = pnp->get_parent(bus->node);
|
||||||
|
|
||||||
|
pnp->uninit_driver(parent);
|
||||||
|
pnp->put_device_node(parent);
|
||||||
|
|
||||||
DELETE_BEN(&bus->status_report_ben);
|
DELETE_BEN(&bus->status_report_ben);
|
||||||
delete_sem(bus->scan_device_sem);
|
delete_sem(bus->scan_device_sem);
|
||||||
@@ -681,7 +693,7 @@ ide_sim_uninit_bus(ide_bus_info *bus)
|
|||||||
scsi->free_dpc(bus->irq_dpc);
|
scsi->free_dpc(bus->irq_dpc);
|
||||||
uninit_synced_pc(&bus->scan_bus_syncinfo);
|
uninit_synced_pc(&bus->scan_bus_syncinfo);
|
||||||
uninit_synced_pc(&bus->disconnect_syncinfo);
|
uninit_synced_pc(&bus->disconnect_syncinfo);
|
||||||
fast_log->stop_log(bus->log);
|
// fast_log->stop_log(bus->log);
|
||||||
|
|
||||||
free(bus);
|
free(bus);
|
||||||
|
|
||||||
@@ -769,9 +781,8 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ FAST_LOG_MODULE_NAME, (module_info **)&fast_log },
|
|
||||||
{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&scsi },
|
{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&scsi },
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -783,23 +794,23 @@ scsi_sim_interface ide_sim_module = {
|
|||||||
0,
|
0,
|
||||||
std_ops,
|
std_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL, // supported devices
|
||||||
|
NULL, // register node
|
||||||
(status_t (*)(device_node_handle, void *, void **))ide_sim_init_bus,
|
(status_t (*)(device_node_handle, void *, void **))ide_sim_init_bus,
|
||||||
(status_t (*)( void *)) ide_sim_uninit_bus,
|
(status_t (*)(void *) ) ide_sim_uninit_bus,
|
||||||
|
|
||||||
NULL,
|
|
||||||
(void (*)(device_node_handle, void *)) ide_sim_bus_removed
|
(void (*)(device_node_handle, void *)) ide_sim_bus_removed
|
||||||
},
|
},
|
||||||
|
|
||||||
(void (*)( scsi_sim_cookie, scsi_ccb * )) sim_scsi_io,
|
(void (*)(scsi_sim_cookie, scsi_ccb *)) sim_scsi_io,
|
||||||
(uchar (*)( scsi_sim_cookie, scsi_ccb * )) sim_abort,
|
(uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_abort,
|
||||||
(uchar (*)( scsi_sim_cookie, uchar, uchar )) sim_reset_device,
|
(uchar (*)(scsi_sim_cookie, uchar, uchar)) sim_reset_device,
|
||||||
(uchar (*)( scsi_sim_cookie, scsi_ccb * )) sim_term_io,
|
(uchar (*)(scsi_sim_cookie, scsi_ccb *)) sim_term_io,
|
||||||
|
|
||||||
(uchar (*)( scsi_sim_cookie, scsi_path_inquiry * )) sim_path_inquiry,
|
(uchar (*)(scsi_sim_cookie, scsi_path_inquiry *))sim_path_inquiry,
|
||||||
(uchar (*)( scsi_sim_cookie )) sim_scan_bus,
|
(uchar (*)(scsi_sim_cookie)) sim_scan_bus,
|
||||||
(uchar (*)( scsi_sim_cookie )) sim_reset_bus,
|
(uchar (*)(scsi_sim_cookie)) sim_reset_bus,
|
||||||
|
|
||||||
(void (*)( scsi_sim_cookie, uchar,
|
(void (*)(scsi_sim_cookie, uchar,
|
||||||
bool*, bool *, uint32 *)) ide_sim_get_restrictions
|
bool*, bool *, uint32 *)) ide_sim_get_restrictions
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
|
*
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
// (for example, the Pegasos (PPC based) also has an ISA bus)
|
// (for example, the Pegasos (PPC based) also has an ISA bus)
|
||||||
|
|
||||||
|
|
||||||
#define ISA_MODULE_NAME "bus_managers/isa/root"
|
#define ISA_MODULE_NAME "bus_managers/isa/root/device_v1"
|
||||||
|
|
||||||
device_manager_info *pnp;
|
device_manager_info *pnp;
|
||||||
|
|
||||||
@@ -96,6 +98,7 @@ static long
|
|||||||
make_isa_dma_table(const void *buffer, long buffer_size, ulong num_bits,
|
make_isa_dma_table(const void *buffer, long buffer_size, ulong num_bits,
|
||||||
isa_dma_entry *table, long num_entries)
|
isa_dma_entry *table, long num_entries)
|
||||||
{
|
{
|
||||||
|
// ToDo: implement this?!
|
||||||
return ENOSYS;
|
return ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +107,7 @@ static status_t
|
|||||||
start_isa_dma(long channel, void *buf, long transfer_count,
|
start_isa_dma(long channel, void *buf, long transfer_count,
|
||||||
uchar mode, uchar e_mode)
|
uchar mode, uchar e_mode)
|
||||||
{
|
{
|
||||||
// TBD
|
// ToDo: implement this?!
|
||||||
// ToDo
|
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +116,7 @@ static long
|
|||||||
start_scattered_isa_dma(long channel, const isa_dma_entry *table,
|
start_scattered_isa_dma(long channel, const isa_dma_entry *table,
|
||||||
uchar mode, uchar emode)
|
uchar mode, uchar emode)
|
||||||
{
|
{
|
||||||
|
// ToDo: implement this?!
|
||||||
return ENOSYS;
|
return ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +124,7 @@ start_scattered_isa_dma(long channel, const isa_dma_entry *table,
|
|||||||
static status_t
|
static status_t
|
||||||
lock_isa_dma_channel(long channel)
|
lock_isa_dma_channel(long channel)
|
||||||
{
|
{
|
||||||
// TBD
|
// ToDo: implement this?!
|
||||||
// ToDo
|
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,14 +132,13 @@ lock_isa_dma_channel(long channel)
|
|||||||
static status_t
|
static status_t
|
||||||
unlock_isa_dma_channel(long channel)
|
unlock_isa_dma_channel(long channel)
|
||||||
{
|
{
|
||||||
// TBD
|
// ToDo: implement this?!
|
||||||
// ToDo
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
isa_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
isa_init_driver(device_node_handle node, void *user_cookie, void **cookie)
|
||||||
{
|
{
|
||||||
*cookie = NULL;
|
*cookie = NULL;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -145,52 +146,61 @@ isa_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
isa_uninit_device(void *cookie)
|
isa_uninit_driver(void *cookie)
|
||||||
{
|
{
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float
|
||||||
|
isa_supports_device(device_node_handle parent, bool *_noConnection)
|
||||||
|
{
|
||||||
|
char *bus;
|
||||||
|
|
||||||
|
// make sure parent is really pnp root
|
||||||
|
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (strcmp(bus, "root")) {
|
||||||
|
free(bus);
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(bus);
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
isa_device_added(device_node_handle parent)
|
isa_register_device(device_node_handle parent)
|
||||||
{
|
{
|
||||||
static const device_attr attrs[] = {
|
static const device_attr attrs[] = {
|
||||||
// info about ourself
|
// info about ourself
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: ISA_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: ISA_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: ISA_DEVICE_TYPE_NAME }},
|
|
||||||
// unique connection
|
// unique connection
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }},
|
||||||
|
|
||||||
// mark as being a bus
|
// mark as being a bus
|
||||||
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
|
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
|
|
||||||
// tell where to look for consumers
|
// tell where to look for child devices
|
||||||
// ToDo: temporary hack to get things started!
|
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "isa" }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "busses/ide/ide_isa/isa/device/v1" }},
|
{ B_DRIVER_FIND_DEVICES_ON_DEMAND, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string: ISA_DRIVERS_DIR "/" }},
|
{ B_DRIVER_EXPLORE_LAST, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
device_node_handle node;
|
return pnp->register_device(parent, attrs, NULL, NULL);
|
||||||
char *parent_type;
|
}
|
||||||
status_t res;
|
|
||||||
|
|
||||||
// make sure parent is really pnp root
|
|
||||||
if (pnp->get_attr_string( parent, PNP_DRIVER_TYPE, &parent_type, false))
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if (strcmp(parent_type, "pnp/root")) {
|
static void
|
||||||
free(parent_type);
|
isa_get_paths(const char ***_bus, const char ***_device)
|
||||||
return B_ERROR;
|
{
|
||||||
}
|
static const char *kBus[] = {"root", NULL};
|
||||||
|
|
||||||
free(parent_type);
|
|
||||||
|
|
||||||
res = pnp->register_device(parent, attrs, NULL, &node);
|
*_bus = kBus;
|
||||||
if (res != B_OK)
|
*_device = NULL;
|
||||||
return res;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -209,7 +219,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -245,15 +255,19 @@ static isa2_module_info isa2_module = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
isa_init_device,
|
isa_supports_device,
|
||||||
isa_uninit_device,
|
isa_register_device,
|
||||||
isa_device_added,
|
isa_init_driver,
|
||||||
NULL
|
isa_uninit_driver,
|
||||||
|
NULL, // removed device
|
||||||
|
NULL, // cleanup device
|
||||||
|
isa_get_paths,
|
||||||
},
|
},
|
||||||
|
|
||||||
// this rescan(); as ISA relies on device drivers to detect their
|
// as ISA relies on device drivers to detect their devices themselves,
|
||||||
// devices themselves, we don't have an universal rescan method
|
// we don't have an universal rescan method
|
||||||
NULL
|
NULL, // register child devices
|
||||||
|
NULL, // rescan bus
|
||||||
},
|
},
|
||||||
|
|
||||||
isa_read_io_8, isa_write_io_8,
|
isa_read_io_8, isa_write_io_8,
|
||||||
@@ -265,12 +279,8 @@ static isa2_module_info isa2_module = {
|
|||||||
start_isa_dma,
|
start_isa_dma,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if !_BUILDING_kernel && !BOOT
|
|
||||||
_EXPORT
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
(module_info *)&isa_module,
|
(module_info *)&isa_module,
|
||||||
(module_info *)&isa2_module,
|
(module_info *)&isa2_module,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ KernelAddon pci : kernel bus_managers :
|
|||||||
pci.cpp
|
pci.cpp
|
||||||
pci_info.cpp
|
pci_info.cpp
|
||||||
pci_module.c
|
pci_module.c
|
||||||
|
pci_device.c
|
||||||
kernel_cpp.cpp
|
kernel_cpp.cpp
|
||||||
: pci_arch_bus_manager.a
|
: pci_arch_bus_manager.a
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,27 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Copyright 2003, Marcus Overhagen. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <PCI.h>
|
#include <PCI.h>
|
||||||
|
|
||||||
#include "util/kernel_cpp.h"
|
#include "util/kernel_cpp.h"
|
||||||
#include "pci_priv.h"
|
#include "pci_priv.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
static PCI *pcidb;
|
|
||||||
|
|
||||||
void
|
bool gIrqRouterAvailable = false;
|
||||||
|
spinlock gConfigLock = 0;
|
||||||
|
|
||||||
|
static PCI *sPCI;
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
pci_init(void)
|
pci_init(void)
|
||||||
{
|
{
|
||||||
pcidb = new PCI;
|
if (pci_io_init() != B_OK) {
|
||||||
|
TRACE(("PCI: pci_io_init failed\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pci_config_init() != B_OK) {
|
||||||
|
TRACE(("PCI: pci_config_init failed\n"));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pci_irq_init() != B_OK)
|
||||||
|
TRACE(("PCI: IRQ router not available\n"));
|
||||||
|
else
|
||||||
|
gIrqRouterAvailable = true;
|
||||||
|
|
||||||
|
sPCI = new PCI;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pci_uninit(void)
|
pci_uninit(void)
|
||||||
{
|
{
|
||||||
delete pcidb;
|
delete sPCI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long
|
long
|
||||||
pci_get_nth_pci_info(long index, pci_info *outInfo)
|
pci_get_nth_pci_info(long index, pci_info *outInfo)
|
||||||
{
|
{
|
||||||
return pcidb->GetNthPciInfo(index, outInfo);
|
return sPCI->GetNthPciInfo(index, outInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Copyright 2003, Marcus Overhagen. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef __PCI_H__
|
||||||
|
#define __PCI_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define TRACE_PCI
|
#define TRACE_PCI
|
||||||
#ifndef TRACE_PCI
|
#ifndef TRACE_PCI
|
||||||
#define TRACE(x)
|
# define TRACE(x) ;
|
||||||
#else
|
#else
|
||||||
#define TRACE(x) dprintf x
|
# define TRACE(x) dprintf x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pci_init(void);
|
|
||||||
void pci_uninit(void);
|
|
||||||
long pci_get_nth_pci_info(long index, pci_info *outInfo);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
struct PCIBus;
|
struct PCIBus;
|
||||||
struct PCIDev;
|
struct PCIDev;
|
||||||
|
|
||||||
struct PCIBus
|
struct PCIBus {
|
||||||
{
|
|
||||||
PCIDev *parent;
|
PCIDev *parent;
|
||||||
uint8 bus;
|
uint8 bus;
|
||||||
PCIDev *child;
|
PCIDev *child;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PCIDev
|
struct PCIDev {
|
||||||
{
|
|
||||||
PCIDev *next;
|
PCIDev *next;
|
||||||
PCIBus *parent;
|
PCIBus *parent;
|
||||||
PCIBus *child;
|
PCIBus *child;
|
||||||
@@ -37,37 +40,48 @@ struct PCIDev
|
|||||||
pci_info info;
|
pci_info info;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PCI
|
class PCI {
|
||||||
{
|
public:
|
||||||
public:
|
PCI();
|
||||||
PCI();
|
~PCI();
|
||||||
~PCI();
|
|
||||||
|
|
||||||
status_t GetNthPciInfo(long index, pci_info *outInfo);
|
status_t GetNthPciInfo(long index, pci_info *outInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DiscoverBus(PCIBus *bus);
|
void DiscoverBus(PCIBus *bus);
|
||||||
void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func);
|
void DiscoverDevice(PCIBus *bus, uint8 dev, uint8 func);
|
||||||
|
|
||||||
PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func);
|
|
||||||
PCIBus *CreateBus(PCIDev *parent, uint8 bus);
|
|
||||||
|
|
||||||
status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo);
|
|
||||||
void ReadPciBasicInfo(PCIDev *dev);
|
|
||||||
void ReadPciHeaderInfo(PCIDev *dev);
|
|
||||||
|
|
||||||
void RefreshDeviceInfo(PCIBus *bus);
|
PCIDev *CreateDevice(PCIBus *parent, uint8 dev, uint8 func);
|
||||||
|
PCIBus *CreateBus(PCIDev *parent, uint8 bus);
|
||||||
uint32 BarSize(uint32 bits, uint32 mask);
|
|
||||||
void GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
|
status_t GetNthPciInfo(PCIBus *bus, long *curindex, long wantindex, pci_info *outInfo);
|
||||||
void GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
|
void ReadPciBasicInfo(PCIDev *dev);
|
||||||
|
void ReadPciHeaderInfo(PCIDev *dev);
|
||||||
private:
|
|
||||||
PCIBus fRootBus;
|
void RefreshDeviceInfo(PCIBus *bus);
|
||||||
|
|
||||||
|
uint32 BarSize(uint32 bits, uint32 mask);
|
||||||
|
void GetBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
|
||||||
|
void GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *address, uint32 *size = 0, uint8 *flags = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PCIBus fRootBus;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status_t pci_init(void);
|
||||||
|
void pci_uninit(void);
|
||||||
|
|
||||||
|
long pci_get_nth_pci_info(long index, pci_info *outInfo);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* __PCI_H__ */
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Copyright 2002-2003, Thomas Kurschel. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
PCI bus manager
|
||||||
|
|
||||||
|
PCI device layer. There is one node per PCI device.
|
||||||
|
The common root is the PCI root node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "pci_priv.h"
|
||||||
|
|
||||||
|
|
||||||
|
// information about one PCI device
|
||||||
|
typedef struct pci_device_info {
|
||||||
|
uint8 bus; // bus number
|
||||||
|
uint8 device; // device number
|
||||||
|
uint8 function; // function number
|
||||||
|
device_node_handle node;
|
||||||
|
pci_root_info *root; // parent, i.e. PCI root
|
||||||
|
char name[32]; // name (for fast log)
|
||||||
|
} pci_device_info;
|
||||||
|
|
||||||
|
|
||||||
|
static uint8
|
||||||
|
pci_device_read_io_8(pci_device_info *device, int mapped_io_addr)
|
||||||
|
{
|
||||||
|
return pci_read_io_8(mapped_io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
pci_device_write_io_8(pci_device_info *device, int mapped_io_addr, uint8 value)
|
||||||
|
{
|
||||||
|
pci_write_io_8(mapped_io_addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint16
|
||||||
|
pci_device_read_io_16(pci_device_info *device, int mapped_io_addr)
|
||||||
|
{
|
||||||
|
return pci_read_io_16(mapped_io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
pci_device_write_io_16(pci_device_info *device, int mapped_io_addr, uint16 value)
|
||||||
|
{
|
||||||
|
pci_write_io_16(mapped_io_addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
pci_device_read_io_32(pci_device_info *device, int mapped_io_addr)
|
||||||
|
{
|
||||||
|
return pci_read_io_32(mapped_io_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pci_device_write_io_32(pci_device_info *device, int mapped_io_addr, uint32 value)
|
||||||
|
{
|
||||||
|
pci_write_io_32(mapped_io_addr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
pci_device_read_pci_config(pci_device_info *device, uint8 offset, uint8 size)
|
||||||
|
{
|
||||||
|
return device->root->read_pci_config(device->bus, device->device,
|
||||||
|
device->function, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
pci_device_write_pci_config(pci_device device, uint8 offset, uint8 size, uint32 value)
|
||||||
|
{
|
||||||
|
return device->root->write_pci_config(device->bus, device->device,
|
||||||
|
device->function, offset, size, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
pci_device_ram_address(pci_device_info *device,
|
||||||
|
const void *physical_address_in_system_memory)
|
||||||
|
{
|
||||||
|
return pci_ram_address(physical_address_in_system_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
pci_device_init_driver(device_node_handle node, void *user_cookie, void **cookie)
|
||||||
|
{
|
||||||
|
uint8 bus, deviceNumber, function;
|
||||||
|
device_node_handle parent;
|
||||||
|
pci_device_info *device;
|
||||||
|
pci_root_info *root;
|
||||||
|
status_t status;
|
||||||
|
void *dummy;
|
||||||
|
|
||||||
|
if (gDeviceManager->get_attr_uint8(node, PCI_DEVICE_BUS_ITEM, &bus, false) != B_OK
|
||||||
|
|| gDeviceManager->get_attr_uint8(node, PCI_DEVICE_DEVICE_ITEM, &deviceNumber, false) != B_OK
|
||||||
|
|| gDeviceManager->get_attr_uint8(node, PCI_DEVICE_FUNCTION_ITEM, &function, false) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
parent = gDeviceManager->get_parent(node);
|
||||||
|
|
||||||
|
status = gDeviceManager->init_driver(parent, NULL, (driver_module_info **)&root, &dummy);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
device = malloc(sizeof(*device));
|
||||||
|
if (device == NULL) {
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
gDeviceManager->put_device_node(parent);
|
||||||
|
|
||||||
|
memset(device, 0, sizeof(*device));
|
||||||
|
|
||||||
|
device->bus = bus;
|
||||||
|
device->device = deviceNumber;
|
||||||
|
device->function = function;
|
||||||
|
device->node = node;
|
||||||
|
device->root = root;
|
||||||
|
|
||||||
|
snprintf(device->name, sizeof(device->name), "pci_device %u:%u:%u",
|
||||||
|
bus, deviceNumber, function);
|
||||||
|
|
||||||
|
*cookie = device;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
err:
|
||||||
|
gDeviceManager->uninit_driver(parent);
|
||||||
|
gDeviceManager->put_device_node(parent);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
pci_device_uninit_driver(void *cookie)
|
||||||
|
{
|
||||||
|
pci_device_info *device = cookie;
|
||||||
|
device_node_handle parent;
|
||||||
|
|
||||||
|
parent = gDeviceManager->get_parent(device->node);
|
||||||
|
gDeviceManager->uninit_driver(parent);
|
||||||
|
gDeviceManager->put_device_node(parent);
|
||||||
|
|
||||||
|
free(device);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
pci_device_std_ops(int32 op, ...)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case B_MODULE_INIT:
|
||||||
|
case B_MODULE_UNINIT:
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pci_device_module_info gPCIDeviceModule = {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
PCI_DEVICE_MODULE_NAME,
|
||||||
|
0,
|
||||||
|
pci_device_std_ops
|
||||||
|
},
|
||||||
|
|
||||||
|
NULL, // supports device
|
||||||
|
NULL, // register device (our parent registered us)
|
||||||
|
pci_device_init_driver,
|
||||||
|
pci_device_uninit_driver,
|
||||||
|
NULL, // removed
|
||||||
|
NULL, // cleanup
|
||||||
|
NULL, // get supported paths
|
||||||
|
},
|
||||||
|
|
||||||
|
pci_device_read_io_8,
|
||||||
|
pci_device_write_io_8,
|
||||||
|
pci_device_read_io_16,
|
||||||
|
pci_device_write_io_16,
|
||||||
|
pci_device_read_io_32,
|
||||||
|
pci_device_write_io_32,
|
||||||
|
|
||||||
|
pci_device_read_pci_config,
|
||||||
|
pci_device_write_pci_config,
|
||||||
|
|
||||||
|
pci_device_ram_address,
|
||||||
|
};
|
||||||
@@ -1,85 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Copyright 2003, Marcus Overhagen. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <device_manager.h>
|
||||||
#include <bus_manager.h>
|
#include <bus_manager.h>
|
||||||
#include <PCI.h>
|
#include <PCI.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "pci_priv.h"
|
#include "pci_priv.h"
|
||||||
#include "pci_info.h"
|
#include "pci_info.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
bool gIrqRouterAvailable = false;
|
|
||||||
spinlock gConfigLock = 0;
|
|
||||||
|
|
||||||
status_t pci_module_init(void);
|
device_manager_info *gDeviceManager;
|
||||||
status_t pci_module_uninit(void);
|
|
||||||
int32 pci_module_std_ops(int32 op, ...);
|
|
||||||
status_t pci_module_rescan(void);
|
|
||||||
|
|
||||||
status_t
|
|
||||||
pci_module_init(void)
|
// name of PCI root module
|
||||||
|
#define PCI_ROOT_MODULE_NAME "bus_managers/pci/root/device_v1"
|
||||||
|
|
||||||
|
|
||||||
|
static float
|
||||||
|
pci_module_supports_device(device_node_handle parent, bool *_noConnection)
|
||||||
{
|
{
|
||||||
TRACE(("PCI: pci_module_init\n"));
|
char *bus;
|
||||||
|
|
||||||
if (B_OK != pci_io_init()) {
|
// make sure parent is really device root
|
||||||
TRACE(("PCI: pci_io_init failed\n"));
|
if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (strcmp(bus, "root")) {
|
||||||
|
free(bus);
|
||||||
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B_OK != pci_config_init()) {
|
free(bus);
|
||||||
TRACE(("PCI: pci_config_init failed\n"));
|
return 1.0;
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (B_OK != pci_irq_init()) {
|
|
||||||
TRACE(("PCI: IRQ router not available\n"));
|
|
||||||
} else {
|
|
||||||
gIrqRouterAvailable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_init();
|
|
||||||
pci_print_info();
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
static status_t
|
||||||
pci_module_uninit(void)
|
pci_module_register_device(device_node_handle parent)
|
||||||
{
|
{
|
||||||
TRACE(("PCI: pci_module_uninit\n"));
|
io_resource resources[2] = {
|
||||||
pci_uninit();
|
{ IO_PORT, PCI_CONFIG_ADDRESS, 8 },
|
||||||
return B_OK;
|
{}
|
||||||
|
};
|
||||||
|
device_attr attrs[] = {
|
||||||
|
// info about ourself
|
||||||
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PCI_ROOT_MODULE_NAME }},
|
||||||
|
// unique connection name
|
||||||
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "PCI" }},
|
||||||
|
|
||||||
|
// mark as being a bus
|
||||||
|
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
|
// search for device drivers once all devices are detected
|
||||||
|
//{ PNP_BUS_DEFER_PROBE, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
|
// don't scan if loaded as we own I/O resources
|
||||||
|
//{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
io_resource_handle resourceHandles[2];
|
||||||
|
device_node_handle node;
|
||||||
|
// char *parent_type;
|
||||||
|
status_t res;
|
||||||
|
|
||||||
|
res = gDeviceManager->acquire_io_resources(resources, resourceHandles);
|
||||||
|
if (res < B_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return gDeviceManager->register_device(parent, attrs, resourceHandles, &node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
static status_t
|
||||||
pci_module_rescan(void)
|
pci_module_register_child_devices(void *cookie)
|
||||||
{
|
{
|
||||||
|
device_node_handle node = cookie;
|
||||||
|
pci_info device;
|
||||||
|
int32 i = 0;
|
||||||
|
|
||||||
|
while (pci_get_nth_pci_info(i, &device) == B_OK) {
|
||||||
|
device_attr attrs[] = {
|
||||||
|
// info about device
|
||||||
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PCI_DEVICE_MODULE_NAME }},
|
||||||
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string:
|
||||||
|
"bus: %"PCI_DEVICE_BUS_ITEM
|
||||||
|
"%, device: %"PCI_DEVICE_DEVICE_ITEM
|
||||||
|
"%, function: %"PCI_DEVICE_FUNCTION_ITEM"%" }},
|
||||||
|
|
||||||
|
// location on PCI bus
|
||||||
|
{ PCI_DEVICE_BUS_ITEM, B_UINT8_TYPE, { ui8: device.bus }},
|
||||||
|
{ PCI_DEVICE_DEVICE_ITEM, B_UINT8_TYPE, { ui8: device.device }},
|
||||||
|
{ PCI_DEVICE_FUNCTION_ITEM, B_UINT8_TYPE, { ui8: device.function }},
|
||||||
|
|
||||||
|
// info about the device
|
||||||
|
{ PCI_DEVICE_VENDOR_ID_ITEM, B_UINT16_TYPE, { ui16: device.vendor_id }},
|
||||||
|
{ PCI_DEVICE_DEVICE_ID_ITEM, B_UINT16_TYPE, { ui16: device.device_id }},
|
||||||
|
{ PCI_DEVICE_SUBSYSTEM_ID_ITEM, B_UINT16_TYPE, { ui16: device.u.h0.subsystem_id }},
|
||||||
|
{ PCI_DEVICE_SUBVENDOR_ID_ITEM, B_UINT16_TYPE, { ui16: device.u.h0.subsystem_vendor_id }},
|
||||||
|
|
||||||
|
{ PCI_DEVICE_BASE_CLASS_ID_ITEM, B_UINT8_TYPE, { ui8: device.class_base }},
|
||||||
|
{ PCI_DEVICE_SUB_CLASS_ID_ITEM, B_UINT8_TYPE, { ui8: device.class_sub }},
|
||||||
|
{ PCI_DEVICE_API_ID_ITEM, B_UINT8_TYPE, { ui8: device.class_api }},
|
||||||
|
|
||||||
|
// consumer specification
|
||||||
|
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "pci" }},
|
||||||
|
// ToDo: this is a hack
|
||||||
|
{ B_DRIVER_DEVICE_TYPE, B_STRING_TYPE, { string: device.class_base == 1 ? "drivers/dev/disk" : "drivers/dev" }},
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
device_node_handle deviceNode;
|
||||||
|
|
||||||
|
gDeviceManager->register_device(node, attrs, NULL, &deviceNode);
|
||||||
|
// currently, we don't care about loosing devices as we cannot do
|
||||||
|
// anything about that but want to register remaining devices (if possible)
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
static void
|
||||||
|
pci_module_get_paths(const char ***_bus, const char ***_device)
|
||||||
|
{
|
||||||
|
static const char *kBus[] = {"root", NULL};
|
||||||
|
|
||||||
|
*_bus = kBus;
|
||||||
|
*_device = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
pci_module_read_config(uint8 bus, uint8 device, uint8 function,
|
||||||
|
uint8 offset, uint8 size)
|
||||||
|
{
|
||||||
|
return pci_read_config(bus, device, function, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
pci_module_write_config(uint8 bus, uint8 device, uint8 function,
|
||||||
|
uint8 offset, uint8 size, uint32 value)
|
||||||
|
{
|
||||||
|
pci_write_config(bus, device, function, offset, size, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
pci_module_init(device_node_handle node, void *user_cookie, void **_cookie)
|
||||||
|
{
|
||||||
|
*_cookie = node;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int32
|
||||||
|
pci_old_module_std_ops(int32 op, ...)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case B_MODULE_INIT:
|
||||||
|
{
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
TRACE(("PCI: pci_module_init\n"));
|
||||||
|
|
||||||
|
status = pci_init();
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
pci_print_info();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_MODULE_UNINIT:
|
||||||
|
TRACE(("PCI: pci_module_uninit\n"));
|
||||||
|
pci_uninit();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int32
|
||||||
pci_module_std_ops(int32 op, ...)
|
pci_module_std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case B_MODULE_INIT:
|
case B_MODULE_INIT:
|
||||||
return pci_module_init();
|
{
|
||||||
|
module_info *module;
|
||||||
|
return get_module(B_PCI_MODULE_NAME, &module);
|
||||||
|
// this serializes our module initialization
|
||||||
|
}
|
||||||
|
|
||||||
case B_MODULE_UNINIT:
|
case B_MODULE_UNINIT:
|
||||||
return pci_module_uninit();
|
return put_module(B_PCI_MODULE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EINVAL;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct pci_module_info pci_module = {
|
static struct pci_module_info sOldPCIModule = {
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
B_PCI_MODULE_NAME,
|
B_PCI_MODULE_NAME,
|
||||||
B_KEEP_LOADED,
|
B_KEEP_LOADED,
|
||||||
pci_module_std_ops
|
pci_old_module_std_ops
|
||||||
},
|
},
|
||||||
pci_module_rescan
|
NULL
|
||||||
},
|
},
|
||||||
&pci_read_io_8,
|
&pci_read_io_8,
|
||||||
&pci_write_io_8,
|
&pci_write_io_8,
|
||||||
@@ -93,8 +233,40 @@ struct pci_module_info pci_module = {
|
|||||||
&pci_ram_address
|
&pci_ram_address
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct pci_root_info sPCIModule = {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{
|
||||||
|
PCI_ROOT_MODULE_NAME,
|
||||||
|
0,
|
||||||
|
pci_module_std_ops
|
||||||
|
},
|
||||||
|
|
||||||
|
pci_module_supports_device,
|
||||||
|
pci_module_register_device,
|
||||||
|
pci_module_init,
|
||||||
|
NULL, // uninit
|
||||||
|
NULL, // removed
|
||||||
|
NULL, // cleanup
|
||||||
|
pci_module_get_paths,
|
||||||
|
},
|
||||||
|
|
||||||
|
pci_module_register_child_devices,
|
||||||
|
NULL, // rescan bus
|
||||||
|
},
|
||||||
|
|
||||||
|
pci_module_read_config,
|
||||||
|
pci_module_write_config
|
||||||
|
};
|
||||||
|
|
||||||
|
module_dependency module_dependencies[] = {
|
||||||
|
{B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
(module_info *)&pci_module,
|
(module_info *)&sOldPCIModule,
|
||||||
|
(module_info *)&sPCIModule,
|
||||||
|
(module_info *)&gPCIDeviceModule,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Copyright 2003, Marcus Overhagen. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef __PCI_PRIV_H__
|
||||||
|
#define __PCI_PRIV_H__
|
||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <device_manager.h>
|
||||||
|
#include <bus/PCI.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
status_t pci_config_init(void);
|
// name of PCI device modules
|
||||||
uint32 pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
|
#define PCI_DEVICE_MODULE_NAME "bus_managers/pci/device_v1"
|
||||||
void pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
|
|
||||||
void * pci_ram_address(const void *physical_address_in_system_memory);
|
|
||||||
|
|
||||||
status_t pci_io_init(void);
|
// I/O port for PCI config space address
|
||||||
uint8 pci_read_io_8(int mapped_io_addr);
|
#define PCI_CONFIG_ADDRESS 0xcf8
|
||||||
void pci_write_io_8(int mapped_io_addr, uint8 value);
|
// I/O port for PCI config space data
|
||||||
uint16 pci_read_io_16(int mapped_io_addr);
|
#define PCI_CONFIG_DATA 0xcfc
|
||||||
void pci_write_io_16(int mapped_io_addr, uint16 value);
|
|
||||||
uint32 pci_read_io_32(int mapped_io_addr);
|
extern device_manager_info *gDeviceManager;
|
||||||
void pci_write_io_32(int mapped_io_addr, uint32 value);
|
|
||||||
|
|
||||||
|
// PCI root.
|
||||||
|
// apart from being the common parent of all PCI devices, it
|
||||||
|
// manages access to PCI config space
|
||||||
|
typedef struct pci_root_info {
|
||||||
|
bus_module_info info;
|
||||||
|
|
||||||
|
// read PCI config space
|
||||||
|
uint32 (*read_pci_config)(uint8 bus, uint8 device, uint8 function,
|
||||||
|
uint8 offset, uint8 size);
|
||||||
|
|
||||||
|
// write PCI config space
|
||||||
|
void (*write_pci_config)(uint8 bus, uint8 device, uint8 function,
|
||||||
|
uint8 offset, uint8 size, uint32 value);
|
||||||
|
} pci_root_info;
|
||||||
|
|
||||||
|
extern pci_device_module_info gPCIDeviceModule;
|
||||||
|
|
||||||
status_t pci_irq_init(void);
|
|
||||||
uint8 pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin);
|
|
||||||
void pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq);
|
|
||||||
|
|
||||||
extern spinlock gConfigLock;
|
extern spinlock gConfigLock;
|
||||||
extern int gMaxBusDevices;
|
extern int gMaxBusDevices;
|
||||||
@@ -37,6 +58,30 @@ extern bool gIrqRouterAvailable;
|
|||||||
restore_interrupts(cpu_status); \
|
restore_interrupts(cpu_status); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status_t pci_config_init(void);
|
||||||
|
uint32 pci_read_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size);
|
||||||
|
void pci_write_config(uint8 bus, uint8 device, uint8 function, uint8 offset, uint8 size, uint32 value);
|
||||||
|
void *pci_ram_address(const void *physical_address_in_system_memory);
|
||||||
|
|
||||||
|
status_t pci_io_init(void);
|
||||||
|
uint8 pci_read_io_8(int mapped_io_addr);
|
||||||
|
void pci_write_io_8(int mapped_io_addr, uint8 value);
|
||||||
|
uint16 pci_read_io_16(int mapped_io_addr);
|
||||||
|
void pci_write_io_16(int mapped_io_addr, uint16 value);
|
||||||
|
uint32 pci_read_io_32(int mapped_io_addr);
|
||||||
|
void pci_write_io_32(int mapped_io_addr, uint32 value);
|
||||||
|
|
||||||
|
status_t pci_irq_init(void);
|
||||||
|
uint8 pci_read_irq(uint8 bus, uint8 device, uint8 function, uint8 pin);
|
||||||
|
void pci_write_irq(uint8 bus, uint8 device, uint8 function, uint8 pin, uint8 irq);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* __PCI_PRIV_H__ */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002-04, Thomas Kurschel. All rights reserved.
|
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of Open SCSI bus manager
|
Part of Open SCSI bus manager
|
||||||
@@ -35,12 +35,16 @@ static status_t
|
|||||||
scsi_bus_raw_init_device(device_node_handle node,
|
scsi_bus_raw_init_device(device_node_handle node,
|
||||||
void *userCookie, void **cookie)
|
void *userCookie, void **cookie)
|
||||||
{
|
{
|
||||||
|
device_node_handle parent = pnp->get_parent(node);
|
||||||
bus_raw_info *bus;
|
bus_raw_info *bus;
|
||||||
scsi_bus_interface *interface;
|
scsi_bus_interface *interface;
|
||||||
scsi_bus bus_cookie;
|
scsi_bus bus_cookie;
|
||||||
|
|
||||||
status_t res = pnp->load_driver(pnp->get_parent(node), NULL,
|
status_t res = pnp->init_driver(parent, NULL,
|
||||||
(driver_module_info **)&interface, (void **)&bus_cookie);
|
(driver_module_info **)&interface, (void **)&bus_cookie);
|
||||||
|
|
||||||
|
pnp->put_device_node(parent);
|
||||||
|
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
@@ -57,11 +61,13 @@ scsi_bus_raw_init_device(device_node_handle node,
|
|||||||
static status_t
|
static status_t
|
||||||
scsi_bus_raw_uninit_device(bus_raw_info *bus)
|
scsi_bus_raw_uninit_device(bus_raw_info *bus)
|
||||||
{
|
{
|
||||||
status_t res;
|
device_node_handle parent = pnp->get_parent(bus->node);
|
||||||
|
status_t status = pnp->uninit_driver(parent);
|
||||||
|
|
||||||
res = pnp->unload_driver(pnp->get_parent(bus->node));
|
pnp->put_device_node(parent);
|
||||||
if (res != B_OK)
|
|
||||||
return res;
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
free(bus);
|
free(bus);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -86,13 +92,11 @@ scsi_bus_raw_probe(device_node_handle parent)
|
|||||||
|
|
||||||
{
|
{
|
||||||
device_attr attributes[] = {
|
device_attr attributes[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
|
||||||
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "bus_raw" }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "bus_raw" }},
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "bus_raw" }},
|
|
||||||
|
|
||||||
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
@@ -185,9 +189,10 @@ pnp_devfs_driver_info scsi_bus_raw_module = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
scsi_bus_raw_probe,
|
||||||
scsi_bus_raw_init_device,
|
scsi_bus_raw_init_device,
|
||||||
(status_t (*) (void *))scsi_bus_raw_uninit_device,
|
(status_t (*) (void *))scsi_bus_raw_uninit_device,
|
||||||
scsi_bus_raw_probe,
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of Open SCSI bus manager
|
Part of Open SCSI bus manager
|
||||||
@@ -182,6 +182,7 @@ scsi_destroy_bus(scsi_bus_info *bus)
|
|||||||
static status_t
|
static status_t
|
||||||
scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
||||||
{
|
{
|
||||||
|
device_node_handle parent;
|
||||||
uint8 path_id;
|
uint8 path_id;
|
||||||
scsi_bus_info *bus;
|
scsi_bus_info *bus;
|
||||||
status_t res;
|
status_t res;
|
||||||
@@ -239,8 +240,13 @@ scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = pnp->load_driver(pnp->get_parent(node), bus,
|
parent = pnp->get_parent(node);
|
||||||
|
|
||||||
|
res = pnp->init_driver(parent, bus,
|
||||||
(driver_module_info **)&bus->interface, (void **)&bus->sim_cookie);
|
(driver_module_info **)&bus->interface, (void **)&bus->sim_cookie);
|
||||||
|
|
||||||
|
pnp->put_device_node(parent);
|
||||||
|
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@@ -264,7 +270,10 @@ err:
|
|||||||
static status_t
|
static status_t
|
||||||
scsi_uninit_bus(scsi_bus_info *bus)
|
scsi_uninit_bus(scsi_bus_info *bus)
|
||||||
{
|
{
|
||||||
pnp->unload_driver(pnp->get_parent(bus->node));
|
device_node_handle parent = pnp->get_parent(bus->node);
|
||||||
|
pnp->uninit_driver(parent);
|
||||||
|
pnp->put_device_node(parent);
|
||||||
|
|
||||||
scsi_destroy_bus(bus);
|
scsi_destroy_bus(bus);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -331,13 +340,15 @@ scsi_bus_interface scsi_bus_module = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL, // supported devices
|
||||||
|
NULL, // register node
|
||||||
scsi_init_bus,
|
scsi_init_bus,
|
||||||
(status_t (*) (void *)) scsi_uninit_bus,
|
(status_t (*)(void *))scsi_uninit_bus,
|
||||||
NULL,
|
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*) (void *)) scsi_scan_bus
|
(status_t (*)(void *))scsi_scan_bus,
|
||||||
|
NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
scsi_inquiry_path,
|
scsi_inquiry_path,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of Open SCSI bus manager
|
Part of Open SCSI bus manager
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_FAST_LOG
|
||||||
static fast_log_event_type scsi_device_events[] = {
|
static fast_log_event_type scsi_device_events[] = {
|
||||||
{ ev_scsi_requeue_request, "ev_scsi_requeue_request" },
|
{ ev_scsi_requeue_request, "ev_scsi_requeue_request" },
|
||||||
{ ev_scsi_resubmit_request, "ev_scsi_resubmit_request" },
|
{ ev_scsi_resubmit_request, "ev_scsi_resubmit_request" },
|
||||||
@@ -34,62 +35,72 @@ static fast_log_event_type scsi_device_events[] = {
|
|||||||
{ ev_copy_sg_data, "ev_copy_sg_data" },
|
{ ev_copy_sg_data, "ev_copy_sg_data" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// free autosense request of device
|
/** free autosense request of device */
|
||||||
static void scsi_free_autosense_request( scsi_device_info *device )
|
|
||||||
|
static void
|
||||||
|
scsi_free_autosense_request(scsi_device_info *device)
|
||||||
{
|
{
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0( 3, "" );
|
||||||
|
|
||||||
if( device->auto_sense_request != NULL ) {
|
if (device->auto_sense_request != NULL) {
|
||||||
scsi_free_ccb( device->auto_sense_request );
|
scsi_free_ccb(device->auto_sense_request);
|
||||||
device->auto_sense_request = NULL;
|
device->auto_sense_request = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( device->auto_sense_area > 0 ) {
|
if (device->auto_sense_area > 0) {
|
||||||
delete_area( device->auto_sense_area );
|
delete_area(device->auto_sense_area);
|
||||||
device->auto_sense_area = 0;
|
device->auto_sense_area = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// free all data of device
|
/** free all data of device */
|
||||||
static void scsi_free_device( scsi_device_info *device )
|
|
||||||
|
static void
|
||||||
|
scsi_free_device(scsi_device_info *device)
|
||||||
{
|
{
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0( 3, "" );
|
||||||
|
|
||||||
scsi_free_emulation_buffer( device );
|
|
||||||
scsi_free_autosense_request( device );
|
|
||||||
|
|
||||||
unregister_kernel_daemon( scsi_dma_buffer_daemon, device );
|
|
||||||
|
|
||||||
scsi_dma_buffer_free( &device->dma_buffer );
|
scsi_free_emulation_buffer(device);
|
||||||
|
scsi_free_autosense_request(device);
|
||||||
DELETE_BEN( &device->dma_buffer_lock );
|
|
||||||
delete_sem( device->dma_buffer_owner );
|
unregister_kernel_daemon(scsi_dma_buffer_daemon, device);
|
||||||
|
|
||||||
if( device->log != NULL )
|
scsi_dma_buffer_free(&device->dma_buffer);
|
||||||
fast_log->stop_log( device->log );
|
|
||||||
|
DELETE_BEN(&device->dma_buffer_lock);
|
||||||
free( device );
|
delete_sem(device->dma_buffer_owner);
|
||||||
|
|
||||||
|
#ifdef USE_FAST_LOG
|
||||||
|
if (device->log != NULL)
|
||||||
|
fast_log->stop_log(device->log);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// copy string src without trailing zero to dst and remove trailing spaces
|
/** copy string src without trailing zero to dst and remove trailing
|
||||||
// size of dst is dst_size, size of src is dst_size-1
|
* spaces size of dst is dst_size, size of src is dst_size-1
|
||||||
static void beautify_string( char *dst, char *src, int dst_size )
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
beautify_string(char *dst, char *src, int dst_size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memcpy( dst, src, dst_size - 1 );
|
memcpy(dst, src, dst_size - 1);
|
||||||
|
|
||||||
for( i = dst_size - 2; i >= 0; --i ) {
|
for (i = dst_size - 2; i >= 0; --i) {
|
||||||
if( dst[i] != ' ' )
|
if (dst[i] != ' ')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dst[i + 1] = 0;
|
dst[i + 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** register new device */
|
/** register new device */
|
||||||
@@ -120,41 +131,32 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
|
|||||||
char product_rev[sizeof( inquiry_data->product_rev ) + 1];
|
char product_rev[sizeof( inquiry_data->product_rev ) + 1];
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// info about driver
|
// info about driver
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_DEVICE_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DEVICE_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_DEVICE_TYPE_NAME }},
|
|
||||||
|
|
||||||
// connection
|
// connection
|
||||||
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
|
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
|
||||||
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
|
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string:
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string:
|
||||||
"target: %"SCSI_DEVICE_TARGET_ID_ITEM
|
"target: %"SCSI_DEVICE_TARGET_ID_ITEM
|
||||||
"%, lun: %"SCSI_DEVICE_TARGET_LUN_ITEM"%" }},
|
"%, lun: %"SCSI_DEVICE_TARGET_LUN_ITEM"%" }},
|
||||||
|
|
||||||
// inquiry data (used for both identification and information)
|
// inquiry data (used for both identification and information)
|
||||||
{ SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE,
|
{ SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE,
|
||||||
{ raw: { inquiry_data, sizeof( *inquiry_data ) }}},
|
{ raw: { inquiry_data, sizeof( *inquiry_data ) }}},
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string:
|
|
||||||
"inquiry: %" SCSI_DEVICE_INQUIRY_ITEM "%" }},
|
|
||||||
|
|
||||||
// some more info for driver loading
|
// some more info for driver loading
|
||||||
{ SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }},
|
{ SCSI_DEVICE_TYPE_ITEM, B_UINT8_TYPE, { ui8: inquiry_data->device_type }},
|
||||||
{ SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }},
|
{ SCSI_DEVICE_VENDOR_ITEM, B_STRING_TYPE, { string: vendor_ident }},
|
||||||
{ SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }},
|
{ SCSI_DEVICE_PRODUCT_ITEM, B_STRING_TYPE, { string: product_ident }},
|
||||||
{ SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }},
|
{ SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }},
|
||||||
|
|
||||||
// description of peripheral drivers
|
// description of peripheral drivers
|
||||||
// ToDo: temporary hack to get things started!
|
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "scsi" }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "drivers/disk/scsi/scsi_dsk/scsi/device/v1" }},
|
// ToDo: mapping is missing
|
||||||
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string:
|
|
||||||
SCSI_PERIPHERAL_DRIVERS_DIR "/"
|
|
||||||
"type: %" SCSI_DEVICE_TYPE_ITEM "%|"
|
|
||||||
", vendor: %" SCSI_DEVICE_VENDOR_ITEM "%|"
|
|
||||||
", product: %" SCSI_DEVICE_PRODUCT_ITEM "%|"
|
|
||||||
", revision: %" SCSI_DEVICE_REVISION_ITEM "%" }},
|
|
||||||
|
|
||||||
// extra restriction of maximum number of blocks per transfer
|
// extra restriction of maximum number of blocks per transfer
|
||||||
{ BLKDEV_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
|
{ BLKDEV_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
|
||||||
|
|
||||||
// atapi emulation
|
// atapi emulation
|
||||||
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
|
{ SCSI_DEVICE_IS_ATAPI_ITEM, B_UINT8_TYPE, { ui8: is_atapi }},
|
||||||
// manual autosense
|
// manual autosense
|
||||||
@@ -179,19 +181,19 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
|
|||||||
|
|
||||||
// create data structure for a device
|
// create data structure for a device
|
||||||
static scsi_device_info *
|
static scsi_device_info *
|
||||||
scsi_create_device( device_node_handle node, scsi_bus_info *bus,
|
scsi_create_device(device_node_handle node, scsi_bus_info *bus,
|
||||||
int target_id, int target_lun)
|
int target_id, int target_lun)
|
||||||
{
|
{
|
||||||
scsi_device_info *device;
|
scsi_device_info *device;
|
||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0( 3, "" );
|
||||||
|
|
||||||
device = (scsi_device_info *)malloc( sizeof( *device ));
|
device = (scsi_device_info *)malloc(sizeof(*device));
|
||||||
if( device == NULL )
|
if (device == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memset( device, 0, sizeof( *device ));
|
memset(device, 0, sizeof(*device));
|
||||||
|
|
||||||
device->lock_count = device->blocked[0] = device->blocked[1] = 0;
|
device->lock_count = device->blocked[0] = device->blocked[1] = 0;
|
||||||
device->sim_overflow = 0;
|
device->sim_overflow = 0;
|
||||||
device->queued_reqs = NULL;
|
device->queued_reqs = NULL;
|
||||||
@@ -200,31 +202,35 @@ scsi_create_device( device_node_handle node, scsi_bus_info *bus,
|
|||||||
device->target_lun = target_lun;
|
device->target_lun = target_lun;
|
||||||
device->valid = true;
|
device->valid = true;
|
||||||
device->node = node;
|
device->node = node;
|
||||||
|
|
||||||
scsi_dma_buffer_init( &device->dma_buffer );
|
|
||||||
|
|
||||||
if( INIT_BEN( &device->dma_buffer_lock, "dma_buffer" ) < 0 )
|
scsi_dma_buffer_init(&device->dma_buffer);
|
||||||
|
|
||||||
|
if (INIT_BEN(&device->dma_buffer_lock, "dma_buffer") < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
device->dma_buffer_owner = create_sem( 1, "dma_buffer" );
|
device->dma_buffer_owner = create_sem(1, "dma_buffer");
|
||||||
if( device->dma_buffer_owner < 0 )
|
if (device->dma_buffer_owner < 0)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
register_kernel_daemon( scsi_dma_buffer_daemon, device, 5 * 10 );
|
register_kernel_daemon(scsi_dma_buffer_daemon, device, 5 * 10);
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
DELETE_BEN( &device->dma_buffer_lock );
|
DELETE_BEN(&device->dma_buffer_lock);
|
||||||
err:
|
err:
|
||||||
free( device );
|
free(device);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare autosense request.
|
|
||||||
// this cannot be done on demand but during init as we may
|
/** prepare autosense request.
|
||||||
// have run out of ccbs when we need it
|
* this cannot be done on demand but during init as we may
|
||||||
static status_t scsi_create_autosense_request( scsi_device_info *device )
|
* have run out of ccbs when we need it
|
||||||
|
*/
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
scsi_create_autosense_request(scsi_device_info *device)
|
||||||
{
|
{
|
||||||
scsi_ccb *request;
|
scsi_ccb *request;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
@@ -232,28 +238,28 @@ static status_t scsi_create_autosense_request( scsi_device_info *device )
|
|||||||
size_t total_size;
|
size_t total_size;
|
||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0( 3, "" );
|
||||||
|
|
||||||
device->auto_sense_request = request = scsi_alloc_ccb( device );
|
device->auto_sense_request = request = scsi_alloc_ccb(device);
|
||||||
if( device->auto_sense_request == NULL )
|
if (device->auto_sense_request == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
total_size = SCSI_MAX_SENSE_SIZE + sizeof( physical_entry );
|
total_size = SCSI_MAX_SENSE_SIZE + sizeof(physical_entry);
|
||||||
total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
total_size = (total_size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||||
|
|
||||||
// allocate buffer for space sense data and S/G list
|
// allocate buffer for space sense data and S/G list
|
||||||
device->auto_sense_area = create_area( "auto_sense",
|
device->auto_sense_area = create_area("auto_sense",
|
||||||
(void **)&buffer, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 0 );
|
(void **)&buffer, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 0);
|
||||||
if( device->auto_sense_area < 0 )
|
if (device->auto_sense_area < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
request->data = buffer;
|
request->data = buffer;
|
||||||
request->data_len = SCSI_MAX_SENSE_SIZE;
|
request->data_len = SCSI_MAX_SENSE_SIZE;
|
||||||
request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE);
|
request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE);
|
||||||
request->sg_cnt = 1;
|
request->sg_cnt = 1;
|
||||||
|
|
||||||
get_memory_map( buffer, SCSI_MAX_SENSE_SIZE,
|
get_memory_map(buffer, SCSI_MAX_SENSE_SIZE,
|
||||||
(physical_entry *)request->sg_list, 1 );
|
(physical_entry *)request->sg_list, 1);
|
||||||
|
|
||||||
// disable auto-autosense, just in case;
|
// disable auto-autosense, just in case;
|
||||||
// make sure no other request overtakes sense request;
|
// make sure no other request overtakes sense request;
|
||||||
// buffer is/must be DMA safe as we cannot risk trouble with
|
// buffer is/must be DMA safe as we cannot risk trouble with
|
||||||
@@ -262,15 +268,15 @@ static status_t scsi_create_autosense_request( scsi_device_info *device )
|
|||||||
SCSI_ORDERED_QTAG | SCSI_DMA_SAFE;
|
SCSI_ORDERED_QTAG | SCSI_DMA_SAFE;
|
||||||
|
|
||||||
cmd = (scsi_cmd_request_sense *)request->cdb;
|
cmd = (scsi_cmd_request_sense *)request->cdb;
|
||||||
request->cdb_len = sizeof( *cmd );
|
request->cdb_len = sizeof(*cmd);
|
||||||
|
|
||||||
memset( cmd, 0, sizeof( *cmd ));
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
cmd->opcode = SCSI_OP_REQUEST_SENSE;
|
cmd->opcode = SCSI_OP_REQUEST_SENSE;
|
||||||
cmd->LUN = device->target_lun;
|
cmd->LUN = device->target_lun;
|
||||||
cmd->alloc_length = SCSI_MAX_SENSE_SIZE;
|
cmd->alloc_length = SCSI_MAX_SENSE_SIZE;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
scsi_free_ccb(request);
|
scsi_free_ccb(request);
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@@ -282,6 +288,7 @@ err:
|
|||||||
static status_t
|
static status_t
|
||||||
scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
||||||
{
|
{
|
||||||
|
device_node_handle parent = pnp->get_parent(node);
|
||||||
scsi_res_inquiry *inquiry_data = NULL;
|
scsi_res_inquiry *inquiry_data = NULL;
|
||||||
uint8 target_id, target_lun, path_id;
|
uint8 target_id, target_lun, path_id;
|
||||||
scsi_bus_info *bus;
|
scsi_bus_info *bus;
|
||||||
@@ -301,13 +308,13 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
(void **)&inquiry_data, &inquiry_data_len, false) != B_OK
|
(void **)&inquiry_data, &inquiry_data_len, false) != B_OK
|
||||||
|| inquiry_data_len != sizeof(*inquiry_data)) {
|
|| inquiry_data_len != sizeof(*inquiry_data)) {
|
||||||
res = B_ERROR;
|
res = B_ERROR;
|
||||||
goto err3;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = pnp->load_driver(pnp->get_parent(node), NULL, &bus_interface,
|
res = pnp->init_driver(parent, NULL, &bus_interface,
|
||||||
(void **)&bus);
|
(void **)&bus);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err3;
|
goto err1;
|
||||||
|
|
||||||
device = scsi_create_device(node, bus, target_id, target_lun);
|
device = scsi_create_device(node, bus, target_id, target_lun);
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
@@ -322,11 +329,13 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
|
|
||||||
sprintf(device->name, "scsi_device %u:%u:%u", path_id, target_id, target_lun);
|
sprintf(device->name, "scsi_device %u:%u:%u", path_id, target_id, target_lun);
|
||||||
|
|
||||||
|
#ifdef USE_FAST_LOG
|
||||||
device->log = fast_log->start_log(device->name, scsi_device_events);
|
device->log = fast_log->start_log(device->name, scsi_device_events);
|
||||||
if (device->log == NULL) {
|
if (device->log == NULL) {
|
||||||
res = B_NO_MEMORY;
|
res = B_NO_MEMORY;
|
||||||
goto err;
|
goto err3;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
device->inquiry_data = *inquiry_data;
|
device->inquiry_data = *inquiry_data;
|
||||||
|
|
||||||
@@ -353,14 +362,14 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
if (device->manual_autosense) {
|
if (device->manual_autosense) {
|
||||||
if (scsi_create_autosense_request(device) != B_OK) {
|
if (scsi_create_autosense_request(device) != B_OK) {
|
||||||
res = B_NO_MEMORY;
|
res = B_NO_MEMORY;
|
||||||
goto err;
|
goto err3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is an ATAPI device, we need an emulation buffer
|
// if this is an ATAPI device, we need an emulation buffer
|
||||||
if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) {
|
if (scsi_init_emulation_buffer(device, SCSI_ATAPI_BUFFER_SIZE) != B_OK) {
|
||||||
res = B_NO_MEMORY;
|
res = B_NO_MEMORY;
|
||||||
goto err;
|
goto err3;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(device->emulation_map, 0, sizeof(device->emulation_map));
|
memset(device->emulation_map, 0, sizeof(device->emulation_map));
|
||||||
@@ -378,13 +387,13 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
*cookie = device;
|
*cookie = device;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err3:
|
||||||
scsi_free_device(device);
|
scsi_free_device(device);
|
||||||
err2:
|
err2:
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(parent);
|
||||||
err3:
|
err1:
|
||||||
if (inquiry_data != NULL)
|
pnp->put_device_node(parent);
|
||||||
free(inquiry_data);
|
free(inquiry_data);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,14 +401,15 @@ err3:
|
|||||||
static status_t
|
static status_t
|
||||||
scsi_uninit_device(scsi_device_info *device)
|
scsi_uninit_device(scsi_device_info *device)
|
||||||
{
|
{
|
||||||
device_node_handle node = device->node;
|
device_node_handle parent = pnp->get_parent(device->node);
|
||||||
|
|
||||||
SHOW_FLOW0(3, "");
|
SHOW_FLOW0(3, "");
|
||||||
|
|
||||||
scsi_free_device(device);
|
scsi_free_device(device);
|
||||||
|
|
||||||
// must unload parent at last as scsi_free_device access it
|
// must unload parent at last as scsi_free_device access it
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(parent);
|
||||||
|
pnp->put_device_node(parent);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -424,11 +434,10 @@ scsi_device_removed(device_node_handle node, scsi_device_info *device)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
scsi_force_get_device( scsi_bus_info *bus, uchar target_id,
|
scsi_force_get_device(scsi_bus_info *bus, uchar target_id,
|
||||||
uchar target_lun, scsi_device_info **res_device)
|
uchar target_lun, scsi_device_info **res_device)
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_DEVICE_TYPE_NAME }},
|
|
||||||
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
|
{ SCSI_DEVICE_TARGET_ID_ITEM, B_UINT8_TYPE, { ui8: target_id }},
|
||||||
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
|
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
@@ -443,15 +452,17 @@ scsi_force_get_device( scsi_bus_info *bus, uchar target_id,
|
|||||||
// very important: only one can use a forced device to avoid double detection
|
// very important: only one can use a forced device to avoid double detection
|
||||||
acquire_sem(bus->scan_lun_lock);
|
acquire_sem(bus->scan_lun_lock);
|
||||||
|
|
||||||
// check whether device registered already
|
// check whether device registered already
|
||||||
node = pnp->find_device(bus->node, attrs);
|
node = NULL;
|
||||||
|
pnp->get_next_child_device(bus->node, &node, attrs);
|
||||||
|
|
||||||
SHOW_FLOW(3, "%p", node);
|
SHOW_FLOW(3, "%p", node);
|
||||||
|
|
||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
// there is one - get it
|
// there is one - get it
|
||||||
res = pnp->load_driver(node, NULL, &driver_interface,
|
res = pnp->init_driver(node, NULL, &driver_interface,
|
||||||
(void **)&device);
|
(void **)&device);
|
||||||
|
pnp->put_device_node(node);
|
||||||
} else {
|
} else {
|
||||||
// device doesn't exist yet - create a temporary one
|
// device doesn't exist yet - create a temporary one
|
||||||
device = scsi_create_device(NULL, bus, target_id, target_lun);
|
device = scsi_create_device(NULL, bus, target_id, target_lun);
|
||||||
@@ -483,7 +494,7 @@ scsi_put_forced_device(scsi_device_info *device)
|
|||||||
|
|
||||||
if (device->node != NULL)
|
if (device->node != NULL)
|
||||||
// device is registered
|
// device is registered
|
||||||
pnp->unload_driver(device->node);
|
pnp->uninit_driver(device->node);
|
||||||
else
|
else
|
||||||
// device is temporary
|
// device is temporary
|
||||||
scsi_free_device(device);
|
scsi_free_device(device);
|
||||||
@@ -534,9 +545,10 @@ scsi_device_interface scsi_device_module = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL, // supported devices
|
||||||
|
NULL, // register node
|
||||||
scsi_init_device,
|
scsi_init_device,
|
||||||
(status_t (*)(void *)) scsi_uninit_device,
|
(status_t (*)(void *)) scsi_uninit_device,
|
||||||
NULL,
|
|
||||||
(void (*)(device_node_handle, void *)) scsi_device_removed
|
(void (*)(device_node_handle, void *)) scsi_device_removed
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of Open SCSI bus manager
|
Part of Open SCSI bus manager
|
||||||
@@ -14,16 +14,13 @@
|
|||||||
|
|
||||||
locked_pool_interface *locked_pool;
|
locked_pool_interface *locked_pool;
|
||||||
device_manager_info *pnp;
|
device_manager_info *pnp;
|
||||||
fast_log_info *fast_log;
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
|
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
|
||||||
{ FAST_LOG_MODULE_NAME, (module_info **)&fast_log },
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
_EXPORT
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
(module_info *)&scsi_for_sim_module,
|
(module_info *)&scsi_for_sim_module,
|
||||||
(module_info *)&scsi_bus_module,
|
(module_info *)&scsi_bus_module,
|
||||||
|
|||||||
@@ -200,8 +200,10 @@ typedef struct scsi_device_info {
|
|||||||
benaphore dma_buffer_lock; // lock between DMA buffer user and clean-up daemon
|
benaphore dma_buffer_lock; // lock between DMA buffer user and clean-up daemon
|
||||||
sem_id dma_buffer_owner; // to be acquired before using DMA buffer
|
sem_id dma_buffer_owner; // to be acquired before using DMA buffer
|
||||||
dma_buffer dma_buffer; // DMA buffer
|
dma_buffer dma_buffer; // DMA buffer
|
||||||
|
|
||||||
|
#ifdef USE_FAST_LOG
|
||||||
fast_log_handle log; // fast log connection
|
fast_log_handle log; // fast log connection
|
||||||
|
#endif
|
||||||
char name[30]; // name for fast log entries
|
char name[30]; // name for fast log entries
|
||||||
|
|
||||||
// buffer used for emulating SCSI commands
|
// buffer used for emulating SCSI commands
|
||||||
|
|||||||
@@ -27,33 +27,20 @@
|
|||||||
static status_t
|
static status_t
|
||||||
scsi_controller_added(device_node_handle parent)
|
scsi_controller_added(device_node_handle parent)
|
||||||
{
|
{
|
||||||
|
char *controller_name;
|
||||||
int path_id;
|
int path_id;
|
||||||
char *str, *controller_name;
|
|
||||||
|
|
||||||
SHOW_FLOW0(4, "");
|
SHOW_FLOW0(4, "");
|
||||||
|
|
||||||
if (pnp->get_attr_string(parent, PNP_DRIVER_TYPE, &str, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if (strcmp(str, SCSI_SIM_TYPE_NAME) != 0) {
|
|
||||||
free(str);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(str);
|
|
||||||
|
|
||||||
if (pnp->get_attr_string(parent, SCSI_DESCRIPTION_CONTROLLER_NAME,
|
if (pnp->get_attr_string(parent, SCSI_DESCRIPTION_CONTROLLER_NAME,
|
||||||
&controller_name, false) != B_OK) {
|
&controller_name, false) != B_OK) {
|
||||||
pnp->get_attr_string(parent, PNP_DRIVER_DRIVER, &str, false);
|
dprintf("scsi: ignored controller - controller name missing\n");
|
||||||
SHOW_ERROR(0, "Ignored controller managed by %s - controller name missing",
|
|
||||||
str);
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
path_id = pnp->create_id(SCSI_PATHID_GENERATOR);
|
path_id = pnp->create_id(SCSI_PATHID_GENERATOR);
|
||||||
|
|
||||||
if (path_id < 0) {
|
if (path_id < 0) {
|
||||||
SHOW_ERROR(0, "Cannot register SCSI controller %s - out of path IDs",
|
dprintf("scsi: Cannot register SCSI controller %s - out of path IDs\n",
|
||||||
controller_name);
|
controller_name);
|
||||||
free(controller_name);
|
free(controller_name);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -64,13 +51,10 @@ scsi_controller_added(device_node_handle parent)
|
|||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// general information
|
// general information
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: SCSI_BUS_TYPE_NAME }},
|
|
||||||
|
|
||||||
// we are a bus
|
// we are a bus
|
||||||
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
|
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
|
||||||
// search for peripheral drivers after bus is fully scanned
|
|
||||||
{ PNP_BUS_DEFER_PROBE, B_UINT8_TYPE, {ui8: 1 }},
|
|
||||||
|
|
||||||
// remember who we are
|
// remember who we are
|
||||||
// (could use the controller name, but probably some software would choke)
|
// (could use the controller name, but probably some software would choke)
|
||||||
@@ -81,7 +65,7 @@ scsi_controller_added(device_node_handle parent)
|
|||||||
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }},
|
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }},
|
||||||
|
|
||||||
// tell internal bus raw driver to register bus' device in devfs
|
// tell internal bus raw driver to register bus' device in devfs
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,9 +99,10 @@ scsi_for_sim_interface scsi_for_sim_module =
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL, // supported devices
|
||||||
|
scsi_controller_added,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
scsi_controller_added,
|
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
|
|
||||||
#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/" PCI_DEVICE_TYPE_NAME
|
#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/device_v1"
|
||||||
#define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1"
|
#define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1"
|
||||||
|
|
||||||
#define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller"
|
#define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller"
|
||||||
@@ -164,6 +164,39 @@ probe_controller(device_node_handle parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float
|
||||||
|
supports_device(device_node_handle parent, bool *_noConnection)
|
||||||
|
{
|
||||||
|
char *bus;
|
||||||
|
uint8 baseClass, subClass;
|
||||||
|
|
||||||
|
// make sure parent is an PCI IDE mass storage host adapter device node
|
||||||
|
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false) != B_OK
|
||||||
|
|| pnp->get_attr_uint8(parent, PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) != B_OK
|
||||||
|
|| pnp->get_attr_uint8(parent, PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (strcmp(bus, "pci") || baseClass != PCI_mass_storage || subClass != PCI_ide) {
|
||||||
|
free(bus);
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(bus);
|
||||||
|
return 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_paths(const char ***_bus, const char ***_device)
|
||||||
|
{
|
||||||
|
static const char *kBus[] = { "pci", NULL };
|
||||||
|
static const char *kDevice[] = { "drivers/dev/disk/ide", NULL };
|
||||||
|
|
||||||
|
*_bus = kBus;
|
||||||
|
*_device = kDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
module_std_ops(int32 op, ...)
|
module_std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
@@ -180,7 +213,7 @@ module_std_ops(int32 op, ...)
|
|||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
@@ -195,10 +228,13 @@ static ide_controller_interface channel_interface = {
|
|||||||
module_std_ops
|
module_std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*)( device_node_handle , void *, void ** )) init_channel,
|
NULL, // supports device
|
||||||
(status_t (*)( void * )) uninit_channel,
|
NULL, // register device
|
||||||
NULL,
|
(status_t (*)(device_node_handle, void *, void **))init_channel,
|
||||||
(void (*)( device_node_handle , void * )) channel_removed
|
(status_t (*)(void *))uninit_channel,
|
||||||
|
(void (*)(device_node_handle, void *))channel_removed,
|
||||||
|
NULL, // cleanup
|
||||||
|
NULL, // get_paths
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*)(ide_channel_cookie,
|
(status_t (*)(ide_channel_cookie,
|
||||||
@@ -226,17 +262,17 @@ static driver_module_info controller_interface = {
|
|||||||
module_std_ops
|
module_std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*)( device_node_handle, void *, void ** )) init_controller,
|
supports_device,
|
||||||
(status_t (*)( void * )) uninit_controller,
|
|
||||||
probe_controller,
|
probe_controller,
|
||||||
(void (*)( device_node_handle, void * )) controller_removed
|
(status_t (*)(device_node_handle, void *, void **)) init_controller,
|
||||||
|
(status_t (*)(void *)) uninit_controller,
|
||||||
|
(void (*)(device_node_handle, void *)) controller_removed,
|
||||||
|
NULL, // cleanup
|
||||||
|
get_paths,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !_BUILDING_kernel && !BOOT
|
|
||||||
_EXPORT
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
(module_info *)&controller_interface,
|
(module_info *)&controller_interface,
|
||||||
(module_info *)&channel_interface,
|
(module_info *)&channel_interface,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
|
|
||||||
|
|
||||||
#define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/"ISA_DEVICE_TYPE_NAME
|
#define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/device_v1"
|
||||||
|
|
||||||
// private node item:
|
// private node item:
|
||||||
// io address of command block
|
// io address of command block
|
||||||
@@ -223,6 +223,27 @@ finish_dma(void *channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float
|
||||||
|
supports_device(device_node_handle parent, bool *_noConnection)
|
||||||
|
{
|
||||||
|
char *bus;
|
||||||
|
|
||||||
|
// make sure parent is really the ISA bus manager
|
||||||
|
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (strcmp(bus, "isa")) {
|
||||||
|
free(bus);
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: check I/O resources for availability?
|
||||||
|
|
||||||
|
free(bus);
|
||||||
|
return 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
init_channel(device_node_handle node, ide_channel ide_channel, channel_info **cookie)
|
init_channel(device_node_handle node, ide_channel ide_channel, channel_info **cookie)
|
||||||
{
|
{
|
||||||
@@ -239,7 +260,7 @@ init_channel(device_node_handle node, ide_channel ide_channel, channel_info **co
|
|||||||
|| pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK)
|
|| pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
if (pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&isa, &dummy) != B_OK)
|
if (pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&isa, &dummy) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
channel = (channel_info *)malloc(sizeof(channel_info));
|
channel = (channel_info *)malloc(sizeof(channel_info));
|
||||||
@@ -275,7 +296,7 @@ err:
|
|||||||
free(channel);
|
free(channel);
|
||||||
|
|
||||||
err0:
|
err0:
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(pnp->get_parent(node));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +314,7 @@ uninit_channel(channel_info *channel)
|
|||||||
|
|
||||||
remove_io_interrupt_handler(channel->intnum, inthand, channel);
|
remove_io_interrupt_handler(channel->intnum, inthand, channel);
|
||||||
|
|
||||||
pnp->unload_driver(pnp->get_parent(channel->node));
|
pnp->uninit_driver(pnp->get_parent(channel->node));
|
||||||
|
|
||||||
free(channel);
|
free(channel);
|
||||||
|
|
||||||
@@ -301,20 +322,18 @@ uninit_channel(channel_info *channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// publish node of ide channel
|
/** publish node of an ide channel */
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
publish_channel(device_node_handle parent, io_resource_handle *resources, uint16 command_block_base,
|
publish_channel(device_node_handle parent, io_resource_handle *resources,
|
||||||
uint16 control_block_base, uint8 intnum, const char *name)
|
uint16 command_block_base, uint16 control_block_base, uint8 intnum,
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// info about ourself and our consumer
|
// info about ourself and our consumer
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_ISA_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "ide_isa" }},
|
|
||||||
// don't scan if loaded as we own I/O resources
|
|
||||||
{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
|
|
||||||
|
|
||||||
// properties of this controller for ide bus manager
|
// properties of this controller for ide bus manager
|
||||||
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
|
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
|
||||||
@@ -363,16 +382,16 @@ probe_channel(device_node_handle parent,
|
|||||||
|
|
||||||
// we assume that every modern PC has an IDE controller, so no
|
// we assume that every modern PC has an IDE controller, so no
|
||||||
// further testing is done (well - I don't really know how to detect the
|
// further testing is done (well - I don't really know how to detect the
|
||||||
// controll, but who cares ;)
|
// controller, but who cares ;)
|
||||||
return publish_channel(parent, resource_handles, command_block_base,
|
return publish_channel(parent, resource_handles, command_block_base,
|
||||||
control_block_base, intnum, name);
|
control_block_base, intnum, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
scan_parent(device_node_handle node)
|
register_device(device_node_handle node)
|
||||||
{
|
{
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0(3, "");
|
||||||
|
|
||||||
// our parent device is the isa bus and all device drivers are Universal,
|
// our parent device is the isa bus and all device drivers are Universal,
|
||||||
// so the pnp_manager tries each ISA driver in turn
|
// so the pnp_manager tries each ISA driver in turn
|
||||||
@@ -386,7 +405,7 @@ scan_parent(device_node_handle node)
|
|||||||
static void
|
static void
|
||||||
channel_removed(device_node_handle node, channel_info *channel)
|
channel_removed(device_node_handle node, channel_info *channel)
|
||||||
{
|
{
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0(3, "");
|
||||||
|
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
// disable access instantly
|
// disable access instantly
|
||||||
@@ -396,6 +415,17 @@ channel_removed(device_node_handle node, channel_info *channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_paths(const char ***_bus, const char ***_device)
|
||||||
|
{
|
||||||
|
static const char *kBus[] = {"isa", NULL};
|
||||||
|
static const char *kDevice[] = {"drivers/dev/disk/ide", NULL};
|
||||||
|
|
||||||
|
*_bus = kBus;
|
||||||
|
*_device = kDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
std_ops(int32 op, ...)
|
std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
@@ -412,7 +442,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -425,10 +455,13 @@ ide_controller_interface isa_controller_interface = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
supports_device,
|
||||||
|
register_device,
|
||||||
(status_t (*)(device_node_handle, void *, void **)) init_channel,
|
(status_t (*)(device_node_handle, void *, void **)) init_channel,
|
||||||
(status_t (*)(void *)) uninit_channel,
|
(status_t (*)(void *)) uninit_channel,
|
||||||
scan_parent,
|
(void (*)(device_node_handle, void *)) channel_removed,
|
||||||
(void (*)(device_node_handle, void *)) channel_removed
|
NULL, // cleanup
|
||||||
|
get_paths
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*)(ide_channel_cookie,
|
(status_t (*)(ide_channel_cookie,
|
||||||
@@ -448,10 +481,7 @@ ide_controller_interface isa_controller_interface = {
|
|||||||
(status_t (*)(ide_channel_cookie)) &finish_dma,
|
(status_t (*)(ide_channel_cookie)) &finish_dma,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !_BUILDING_kernel && !BOOT
|
|
||||||
_EXPORT
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
(module_info *)&isa_controller_interface,
|
(module_info *)&isa_controller_interface,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -22,11 +22,9 @@
|
|||||||
|
|
||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
|
|
||||||
#define PROMISE_TX2_CONTROLLER_MODULE_NAME "busses/ide/promise_tx2/" PCI_DEVICE_TYPE_NAME
|
#define PROMISE_TX2_CONTROLLER_MODULE_NAME "busses/ide/promise_tx2/device_v1"
|
||||||
#define PROMISE_TX2_CHANNEL_MODULE_NAME "busses/ide/promise_tx2/channel/v1"
|
#define PROMISE_TX2_CHANNEL_MODULE_NAME "busses/ide/promise_tx2/channel/v1"
|
||||||
|
|
||||||
#define PROMISE_TX2_CONTROLLER_TYPE_NAME "promise tx2 controller"
|
|
||||||
|
|
||||||
|
|
||||||
static ide_for_controller_interface *ide;
|
static ide_for_controller_interface *ide;
|
||||||
static ide_adapter_interface *ide_adapter;
|
static ide_adapter_interface *ide_adapter;
|
||||||
@@ -190,10 +188,7 @@ publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intn
|
|||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// info about ourself and our consumer
|
// info about ourself and our consumer
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_TYPE_NAME }},
|
|
||||||
// don't scan if loaded as we own I/O resources
|
|
||||||
{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
|
|
||||||
|
|
||||||
// properties of this controller for ide bus manager
|
// properties of this controller for ide bus manager
|
||||||
// there are always max. 2 devices
|
// there are always max. 2 devices
|
||||||
@@ -273,7 +268,7 @@ probe_controller(device_node_handle parent)
|
|||||||
|
|
||||||
SHOW_FLOW0(3, "");
|
SHOW_FLOW0(3, "");
|
||||||
|
|
||||||
if (pnp->load_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
if (pnp->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4);
|
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4);
|
||||||
@@ -297,12 +292,12 @@ probe_controller(device_node_handle parent)
|
|||||||
command_block_base[1], control_block_base[1], bus_master_base, intnum, false,
|
command_block_base[1], control_block_base[1], bus_master_base, intnum, false,
|
||||||
"Secondary Channel", &channels[1], false);
|
"Secondary Channel", &channels[1], false);
|
||||||
|
|
||||||
pnp->unload_driver(parent);
|
pnp->uninit_driver(parent);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
pnp->unload_driver(parent);
|
pnp->uninit_driver(parent);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +318,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
@@ -338,9 +333,10 @@ static ide_controller_interface channel_interface = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL, // supported devices
|
||||||
|
NULL,
|
||||||
(status_t (*)( device_node_handle , void *, void ** )) init_channel,
|
(status_t (*)( device_node_handle , void *, void ** )) init_channel,
|
||||||
(status_t (*)( void * )) uninit_channel,
|
(status_t (*)( void * )) uninit_channel,
|
||||||
NULL,
|
|
||||||
(void (*)( device_node_handle , void * )) channel_removed
|
(void (*)( device_node_handle , void * )) channel_removed
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -369,17 +365,15 @@ static driver_module_info controller_interface = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
probe_controller,
|
||||||
(status_t (*)(device_node_handle, void *, void **)) init_controller,
|
(status_t (*)(device_node_handle, void *, void **)) init_controller,
|
||||||
(status_t (*)(void *)) uninit_controller,
|
(status_t (*)(void *)) uninit_controller,
|
||||||
probe_controller,
|
|
||||||
(void (*)(device_node_handle, void *)) controller_removed
|
(void (*)(device_node_handle, void *)) controller_removed
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !_BUILDING_kernel && !BOOT
|
|
||||||
_EXPORT
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
(module_info *)&controller_interface,
|
(module_info *)&controller_interface,
|
||||||
(module_info *)&channel_interface,
|
(module_info *)&channel_interface,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ raw_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
device->node = node;
|
device->node = node;
|
||||||
|
|
||||||
// register it everywhere
|
// register it everywhere
|
||||||
res = pnp->load_driver(pnp->get_parent(node), NULL,
|
res = pnp->init_driver(pnp->get_parent(node), NULL,
|
||||||
(driver_module_info **)&device->scsi, (void **)&device->scsi_device);
|
(driver_module_info **)&device->scsi, (void **)&device->scsi_device);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err;
|
goto err;
|
||||||
@@ -176,7 +176,7 @@ err:
|
|||||||
static status_t
|
static status_t
|
||||||
raw_uninit_device(raw_device_info *device)
|
raw_uninit_device(raw_device_info *device)
|
||||||
{
|
{
|
||||||
pnp->unload_driver(pnp->get_parent(device->node));
|
pnp->uninit_driver(pnp->get_parent(device->node));
|
||||||
free(device);
|
free(device);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -192,21 +192,9 @@ raw_device_added(device_node_handle node)
|
|||||||
{
|
{
|
||||||
uint8 path_id, target_id, target_lun;
|
uint8 path_id, target_id, target_lun;
|
||||||
char name[100];
|
char name[100];
|
||||||
char *str;
|
|
||||||
|
|
||||||
SHOW_FLOW0(3, "");
|
SHOW_FLOW0(3, "");
|
||||||
|
|
||||||
// make sure we can handle this parent device
|
|
||||||
if (pnp->get_attr_string(node, PNP_DRIVER_TYPE, &str, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if (strcmp(str, SCSI_DEVICE_TYPE_NAME) != 0) {
|
|
||||||
free(str);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(str);
|
|
||||||
|
|
||||||
// compose name
|
// compose name
|
||||||
if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK
|
if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK
|
||||||
|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK
|
|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK
|
||||||
@@ -221,18 +209,16 @@ raw_device_added(device_node_handle node)
|
|||||||
// ready to register
|
// ready to register
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }},
|
||||||
|
|
||||||
// default connection is used by peripheral drivers, and as we don't
|
// default connection is used by peripheral drivers, and as we don't
|
||||||
// want to kick them out, we use concurrent "raw" connection
|
// want to kick them out, we use concurrent "raw" connection
|
||||||
// (btw: this shows nicely that something goes wrong: one device
|
// (btw: this shows nicely that something goes wrong: one device
|
||||||
// and two drivers means begging for trouble)
|
// and two drivers means begging for trouble)
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "raw" }},
|
|
||||||
|
|
||||||
// we want devfs on top of us
|
// we want devfs on top of us (who wouldn't?)
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
|
||||||
// tell which name we want to have in devfs
|
// tell which name we want to have in devfs
|
||||||
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
@@ -258,7 +244,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -270,9 +256,10 @@ pnp_devfs_driver_info scsi_raw_module = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
raw_device_added,
|
||||||
raw_init_device,
|
raw_init_device,
|
||||||
(status_t (*) (void *))raw_uninit_device,
|
(status_t (*) (void *))raw_uninit_device,
|
||||||
raw_device_added,
|
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ cd_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
// we don't verify type - in worst case, the device doesn't work
|
// we don't verify type - in worst case, the device doesn't work
|
||||||
|
|
||||||
// register it everywhere
|
// register it everywhere
|
||||||
res = pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
|
res = pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
|
||||||
(void **)&device->scsi_device);
|
(void **)&device->scsi_device);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
@@ -71,7 +71,7 @@ cd_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err3:
|
err3:
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(pnp->get_parent(node));
|
||||||
err2:
|
err2:
|
||||||
err1:
|
err1:
|
||||||
free(device);
|
free(device);
|
||||||
@@ -83,7 +83,7 @@ status_t
|
|||||||
cd_uninit_device(cd_device_info *device)
|
cd_uninit_device(cd_device_info *device)
|
||||||
{
|
{
|
||||||
scsi_periph->unregister_device(device->scsi_periph_device);
|
scsi_periph->unregister_device(device->scsi_periph_device);
|
||||||
pnp->unload_driver(pnp->get_parent(device->node));
|
pnp->uninit_driver(pnp->get_parent(device->node));
|
||||||
free(device);
|
free(device);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -98,7 +98,6 @@ cd_uninit_device(cd_device_info *device)
|
|||||||
status_t
|
status_t
|
||||||
cd_device_added(device_node_handle node)
|
cd_device_added(device_node_handle node)
|
||||||
{
|
{
|
||||||
char *str = NULL;
|
|
||||||
uint8 device_type;
|
uint8 device_type;
|
||||||
scsi_res_inquiry *device_inquiry = NULL;
|
scsi_res_inquiry *device_inquiry = NULL;
|
||||||
size_t inquiry_len;
|
size_t inquiry_len;
|
||||||
@@ -107,11 +106,6 @@ cd_device_added(device_node_handle node)
|
|||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0( 3, "" );
|
||||||
|
|
||||||
// make sure we can handle this parent device
|
|
||||||
if( pnp->get_attr_string( node, PNP_DRIVER_TYPE, &str, false ) != B_OK ||
|
|
||||||
strcmp( str, SCSI_DEVICE_TYPE_NAME ) != 0 )
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// check whether it's really a CD-ROM or a WORM
|
// check whether it's really a CD-ROM or a WORM
|
||||||
if( pnp->get_attr_uint8( node, SCSI_DEVICE_TYPE_ITEM,
|
if( pnp->get_attr_uint8( node, SCSI_DEVICE_TYPE_ITEM,
|
||||||
&device_type, true ) != B_OK ||
|
&device_type, true ) != B_OK ||
|
||||||
@@ -145,11 +139,10 @@ cd_device_added(device_node_handle node)
|
|||||||
// ready to register
|
// ready to register
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_CD_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_CD_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: BLKDEV_TYPE_NAME }},
|
// we always want blkman on top of us
|
||||||
// we always want blkdev on top of us
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
|
// tell blkman whether the device is removable
|
||||||
// tell blkdev whether the device is removable
|
|
||||||
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
|
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
|
||||||
// tell which name we want to have in devfs
|
// tell which name we want to have in devfs
|
||||||
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
||||||
@@ -162,14 +155,12 @@ cd_device_added(device_node_handle node)
|
|||||||
res = pnp->register_device(node, attrs, NULL, &node);
|
res = pnp->register_device(node, attrs, NULL, &node);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
free(str);
|
|
||||||
free(device_inquiry);
|
free(device_inquiry);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
free(str);
|
|
||||||
free(device_inquiry);
|
free(device_inquiry);
|
||||||
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ das_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
// register it everywhere
|
// register it everywhere
|
||||||
res = pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
|
res = pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
|
||||||
(void **)&device->scsi_device);
|
(void **)&device->scsi_device);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
@@ -71,7 +71,7 @@ das_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
err4:
|
err4:
|
||||||
scsi_periph->unregister_device(device->scsi_periph_device);
|
scsi_periph->unregister_device(device->scsi_periph_device);
|
||||||
err3:
|
err3:
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(pnp->get_parent(node));
|
||||||
err2:
|
err2:
|
||||||
err1:
|
err1:
|
||||||
free(device);
|
free(device);
|
||||||
@@ -83,7 +83,7 @@ status_t
|
|||||||
das_uninit_device(das_device_info *device)
|
das_uninit_device(das_device_info *device)
|
||||||
{
|
{
|
||||||
scsi_periph->unregister_device(device->scsi_periph_device);
|
scsi_periph->unregister_device(device->scsi_periph_device);
|
||||||
pnp->unload_driver(pnp->get_parent(device->node));
|
pnp->uninit_driver(pnp->get_parent(device->node));
|
||||||
free(device);
|
free(device);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -98,18 +98,12 @@ das_uninit_device(das_device_info *device)
|
|||||||
status_t
|
status_t
|
||||||
das_device_added(device_node_handle node)
|
das_device_added(device_node_handle node)
|
||||||
{
|
{
|
||||||
char *str = NULL;
|
|
||||||
scsi_res_inquiry *device_inquiry = NULL;
|
scsi_res_inquiry *device_inquiry = NULL;
|
||||||
uint8 device_type;
|
uint8 device_type;
|
||||||
size_t inquiry_len;
|
size_t inquiry_len;
|
||||||
char *name;
|
char *name;
|
||||||
uint32 max_blocks;
|
uint32 max_blocks;
|
||||||
|
|
||||||
// make sure we can handle this parent device
|
|
||||||
if (pnp->get_attr_string(node, PNP_DRIVER_TYPE, &str, false) != B_OK
|
|
||||||
|| strcmp(str, SCSI_DEVICE_TYPE_NAME) != 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// check whether it's really a Direct Access Device
|
// check whether it's really a Direct Access Device
|
||||||
if (pnp->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK
|
if (pnp->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK
|
||||||
|| device_type != scsi_dev_direct_access)
|
|| device_type != scsi_dev_direct_access)
|
||||||
@@ -141,11 +135,10 @@ das_device_added(device_node_handle node)
|
|||||||
// ready to register
|
// ready to register
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: BLKDEV_TYPE_NAME }},
|
// we always want blkman on top of us
|
||||||
// we always want blkdev on top of us
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
|
// tell blkman whether the device is removable
|
||||||
// tell blkdev whether the device is removable
|
|
||||||
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
|
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->RMB }},
|
||||||
// tell which name we want to have in devfs
|
// tell which name we want to have in devfs
|
||||||
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
||||||
@@ -159,14 +152,12 @@ das_device_added(device_node_handle node)
|
|||||||
status_t res = pnp->register_device(node, attrs, NULL, &node);
|
status_t res = pnp->register_device(node, attrs, NULL, &node);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
free(str);
|
|
||||||
free(device_inquiry);
|
free(device_inquiry);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
free(str);
|
|
||||||
free(device_inquiry);
|
free(device_inquiry);
|
||||||
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
#include "scsi_dsk_int.h"
|
#include "scsi_dsk_int.h"
|
||||||
#include <scsi.h>
|
#include <scsi.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
extern blkdev_interface das_interface;
|
extern blkdev_interface das_interface;
|
||||||
@@ -222,6 +224,37 @@ das_ioctl(das_handle_info *handle, int op, void *buf, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static float
|
||||||
|
das_supports_device(device_node_handle parent, bool *_noConnection)
|
||||||
|
{
|
||||||
|
char *bus;
|
||||||
|
|
||||||
|
// make sure parent is really the SCSI bus manager
|
||||||
|
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (strcmp(bus, "scsi")) {
|
||||||
|
free(bus);
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: check SCSI device type! (must be "disk")
|
||||||
|
|
||||||
|
free(bus);
|
||||||
|
return 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
das_get_paths(const char ***_bus, const char ***_device)
|
||||||
|
{
|
||||||
|
static const char *kBus[] = { "scsi", NULL };
|
||||||
|
|
||||||
|
*_bus = kBus;
|
||||||
|
*_device = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
std_ops(int32 op, ...)
|
std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
@@ -239,7 +272,7 @@ std_ops(int32 op, ...)
|
|||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ SCSI_PERIPH_MODULE_NAME, (module_info **)&scsi_periph },
|
{ SCSI_PERIPH_MODULE_NAME, (module_info **)&scsi_periph },
|
||||||
{ BLKMAN_FOR_DRIVER_MODULE_NAME, (module_info **)&blkman },
|
{ BLKMAN_FOR_DRIVER_MODULE_NAME, (module_info **)&blkman },
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -251,10 +284,13 @@ blkdev_interface scsi_dsk_module = {
|
|||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
das_supports_device,
|
||||||
|
das_device_added,
|
||||||
das_init_device,
|
das_init_device,
|
||||||
(status_t (*) (void *))das_uninit_device,
|
(status_t (*) (void *))das_uninit_device,
|
||||||
das_device_added,
|
NULL, // remove device
|
||||||
NULL
|
NULL, // cleanup device
|
||||||
|
das_get_paths,
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*)(blkdev_device_cookie, blkdev_handle_cookie *)) &das_open,
|
(status_t (*)(blkdev_device_cookie, blkdev_handle_cookie *)) &das_open,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of Open SCSI Disk Driver
|
Part of Open SCSI Disk Driver
|
||||||
@@ -17,6 +17,6 @@
|
|||||||
|
|
||||||
#include <device_manager.h>
|
#include <device_manager.h>
|
||||||
|
|
||||||
#define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/"SCSI_DEVICE_TYPE_NAME
|
#define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/device_v1"
|
||||||
|
|
||||||
#endif
|
#endif /* _SCSI_DSK_H */
|
||||||
|
|||||||
@@ -340,30 +340,16 @@ blkman_ioctl(blkman_handle_info *handle, uint32 op, void *buf, size_t len)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
blkman_probe(device_node_handle parent)
|
blkman_register_device(device_node_handle parent)
|
||||||
{
|
{
|
||||||
char *str;
|
|
||||||
|
|
||||||
TRACE(("blkman_probe()\n"));
|
TRACE(("blkman_probe()\n"));
|
||||||
|
|
||||||
// make sure we can handle this parent device
|
|
||||||
if (pnp->get_attr_string(parent, "type", &str, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if (strcmp(str, BLKDEV_TYPE_NAME) != 0) {
|
|
||||||
free(str);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(str);
|
|
||||||
|
|
||||||
// ready to register at devfs
|
// ready to register at devfs
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: BLKMAN_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
|
|
||||||
// we always want devfs on top of us
|
// we always want devfs on top of us
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "blkman" }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "blkman" }},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
@@ -505,7 +491,7 @@ blkman_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|||||||
device->params = params;
|
device->params = params;
|
||||||
device->is_bios_drive = is_bios_drive != 0;
|
device->is_bios_drive = is_bios_drive != 0;
|
||||||
|
|
||||||
res = pnp->load_driver(pnp->get_parent(node), device,
|
res = pnp->init_driver(pnp->get_parent(node), device,
|
||||||
(driver_module_info **)&device->interface, (void **)&device->cookie);
|
(driver_module_info **)&device->interface, (void **)&device->cookie);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
goto err4;
|
goto err4;
|
||||||
@@ -525,7 +511,7 @@ err2:
|
|||||||
free(device);
|
free(device);
|
||||||
err1:
|
err1:
|
||||||
free(name);
|
free(name);
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(pnp->get_parent(node));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +519,7 @@ err1:
|
|||||||
static status_t
|
static status_t
|
||||||
blkman_uninit_device(blkman_device_info *device)
|
blkman_uninit_device(blkman_device_info *device)
|
||||||
{
|
{
|
||||||
pnp->unload_driver(pnp->get_parent(device->node));
|
pnp->uninit_driver(pnp->get_parent(device->node));
|
||||||
|
|
||||||
locked_pool->destroy(device->phys_vecs_pool);
|
locked_pool->destroy(device->phys_vecs_pool);
|
||||||
benaphore_destroy(&device->lock);
|
benaphore_destroy(&device->lock);
|
||||||
@@ -614,7 +600,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
|
{ LOCKED_POOL_MODULE_NAME, (module_info **)&locked_pool },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
@@ -628,11 +614,14 @@ pnp_devfs_driver_info blkman_module = {
|
|||||||
|
|
||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL, // supports device
|
||||||
|
blkman_register_device,
|
||||||
blkman_init_device,
|
blkman_init_device,
|
||||||
(status_t (*)( void * )) blkman_uninit_device,
|
(status_t (*)( void * )) blkman_uninit_device,
|
||||||
blkman_probe,
|
blkman_remove,
|
||||||
blkman_remove
|
NULL, // cleanup
|
||||||
|
NULL, // get paths
|
||||||
},
|
},
|
||||||
|
|
||||||
(status_t (*)(void *, uint32, void **))blkman_open,
|
(status_t (*)(void *, uint32, void **))blkman_open,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fast logging facilities.
|
Fast logging facilities.
|
||||||
@@ -568,7 +568,7 @@ fast_log_std_ops(int32 op, ...)
|
|||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -81,9 +81,8 @@ fast_log_create_devfs_entry(void)
|
|||||||
{
|
{
|
||||||
status_t res;
|
status_t res;
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: FAST_LOG_DEVFS_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: FAST_LOG_DEVFS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_DEVFS_TYPE_NAME }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "fast_log" }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "fast_log" }},
|
||||||
|
|
||||||
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: FAST_LOG_DEVFS_NAME }},
|
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: FAST_LOG_DEVFS_NAME }},
|
||||||
@@ -136,12 +135,14 @@ pnp_devfs_driver_info fast_log_devfs_module = {
|
|||||||
fast_log_devfs_std_ops
|
fast_log_devfs_std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
|
||||||
fast_log_devfs_init_device,
|
fast_log_devfs_init_device,
|
||||||
fast_log_devfs_uninit_device,
|
fast_log_devfs_uninit_device,
|
||||||
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
fast_log_devfs_open,
|
fast_log_devfs_open,
|
||||||
|
|||||||
@@ -301,17 +301,18 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel)
|
|||||||
if (status.active) {
|
if (status.active) {
|
||||||
SHOW_ERROR0( 2, "DMA transfer aborted" );
|
SHOW_ERROR0( 2, "DMA transfer aborted" );
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
} else {
|
|
||||||
SHOW_ERROR0( 2, "DMA transfer: buffer underrun" );
|
|
||||||
return B_DEV_DATA_UNDERRUN;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (status.active) {
|
SHOW_ERROR0( 2, "DMA transfer: buffer underrun" );
|
||||||
SHOW_ERROR0( 2, "DMA transfer: buffer too large" );
|
return B_DEV_DATA_UNDERRUN;
|
||||||
return B_DEV_DATA_OVERRUN;
|
|
||||||
} else
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status.active) {
|
||||||
|
SHOW_ERROR0( 2, "DMA transfer: buffer too large" );
|
||||||
|
return B_DEV_DATA_OVERRUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -336,7 +337,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
|
|||||||
|| pnp->get_attr_uint8(node, IDE_ADAPTER_IS_PRIMARY, &is_primary, false) != B_OK)
|
|| pnp->get_attr_uint8(node, IDE_ADAPTER_IS_PRIMARY, &is_primary, false) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
if (pnp->load_driver(pnp->get_parent(node), NULL, NULL, (void **)&controller) != B_OK)
|
if (pnp->init_driver(pnp->get_parent(node), NULL, NULL, (void **)&controller) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
channel = (ide_adapter_channel_info *)malloc(total_data_size);
|
channel = (ide_adapter_channel_info *)malloc(total_data_size);
|
||||||
@@ -389,7 +390,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
|
|||||||
err3:
|
err3:
|
||||||
delete_area(channel->prd_area);
|
delete_area(channel->prd_area);
|
||||||
err2:
|
err2:
|
||||||
pnp->unload_driver(pnp->get_parent(node));
|
pnp->uninit_driver(pnp->get_parent(node));
|
||||||
err:
|
err:
|
||||||
free(channel);
|
free(channel);
|
||||||
|
|
||||||
@@ -410,7 +411,7 @@ ide_adapter_uninit_channel(ide_adapter_channel_info *channel)
|
|||||||
|
|
||||||
remove_io_interrupt_handler(channel->intnum, channel->inthand, channel);
|
remove_io_interrupt_handler(channel->intnum, channel->inthand, channel);
|
||||||
|
|
||||||
pnp->unload_driver( pnp->get_parent(channel->node));
|
pnp->uninit_driver( pnp->get_parent(channel->node));
|
||||||
|
|
||||||
delete_area(channel->prd_area);
|
delete_area(channel->prd_area);
|
||||||
free(channel);
|
free(channel);
|
||||||
@@ -441,14 +442,10 @@ ide_adapter_publish_channel(device_node_handle controller_node,
|
|||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// info about ourself and our consumer
|
// info about ourself and our consumer
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: channel_module_name }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: channel_module_name }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: IDE_BUS_TYPE_NAME }},
|
{ B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "IDE PCI" }},
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: name }},
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "IDE PCI" }},
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
||||||
|
|
||||||
// disable automatic rescan as we register channels manually
|
|
||||||
{ PNP_DRIVER_NEVER_RESCAN, B_UINT8_TYPE, { ui8 : 1 }},
|
|
||||||
|
|
||||||
// private data to identify channel
|
// private data to identify channel
|
||||||
{ IDE_ADAPTER_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
|
{ IDE_ADAPTER_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
|
||||||
@@ -459,7 +456,7 @@ ide_adapter_publish_channel(device_node_handle controller_node,
|
|||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
SHOW_FLOW0( 2, "" );
|
SHOW_FLOW0(2, "");
|
||||||
|
|
||||||
return pnp->register_device(controller_node, attrs, resources, node);
|
return pnp->register_device(controller_node, attrs, resources, node);
|
||||||
}
|
}
|
||||||
@@ -557,7 +554,7 @@ ide_adapter_init_controller(device_node_handle node, void *user_cookie,
|
|||||||
if (pnp->get_attr_uint16(node, IDE_ADAPTER_BUS_MASTER_BASE, &bus_master_base, false) != B_OK)
|
if (pnp->get_attr_uint16(node, IDE_ADAPTER_BUS_MASTER_BASE, &bus_master_base, false) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
if (pnp->load_driver(pnp->get_parent(node), NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
if (pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
controller = (ide_adapter_controller_info *)malloc(total_data_size);
|
controller = (ide_adapter_controller_info *)malloc(total_data_size);
|
||||||
@@ -579,7 +576,7 @@ ide_adapter_init_controller(device_node_handle node, void *user_cookie,
|
|||||||
static status_t
|
static status_t
|
||||||
ide_adapter_uninit_controller(ide_adapter_controller_info *controller)
|
ide_adapter_uninit_controller(ide_adapter_controller_info *controller)
|
||||||
{
|
{
|
||||||
pnp->unload_driver(pnp->get_parent(controller->node));
|
pnp->uninit_driver(pnp->get_parent(controller->node));
|
||||||
|
|
||||||
free(controller);
|
free(controller);
|
||||||
|
|
||||||
@@ -609,10 +606,7 @@ ide_adapter_publish_controller(device_node_handle parent, uint16 bus_master_base
|
|||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
// info about ourself and our consumer
|
// info about ourself and our consumer
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: controller_driver }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: controller_driver }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: controller_driver_type }},
|
|
||||||
// don't scan if loaded as we own I/O resources
|
|
||||||
{ PNP_DRIVER_NO_LIVE_RESCAN, B_UINT8_TYPE, { ui8: 1 }},
|
|
||||||
|
|
||||||
// properties of this controller for ide bus manager
|
// properties of this controller for ide bus manager
|
||||||
// there are always max. 2 devices
|
// there are always max. 2 devices
|
||||||
@@ -699,7 +693,7 @@ ide_adapter_probe_controller(device_node_handle parent, const char *controller_d
|
|||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
SHOW_FLOW0( 3, "" );
|
||||||
|
|
||||||
if (pnp->load_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
if (pnp->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4 );
|
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4 );
|
||||||
@@ -726,12 +720,12 @@ ide_adapter_probe_controller(device_node_handle parent, const char *controller_d
|
|||||||
can_dma, command_block_base[0], control_block_base[0], bus_master_base,
|
can_dma, command_block_base[0], control_block_base[0], bus_master_base,
|
||||||
intnum, false, "Secondary Channel", &channels[1], supports_compatibility_mode);
|
intnum, false, "Secondary Channel", &channels[1], supports_compatibility_mode);
|
||||||
|
|
||||||
pnp->unload_driver(parent);
|
pnp->uninit_driver(parent);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
pnp->unload_driver(parent);
|
pnp->uninit_driver(parent);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,7 +746,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -777,7 +771,6 @@ static ide_adapter_interface adapter_interface = {
|
|||||||
ide_adapter_start_dma,
|
ide_adapter_start_dma,
|
||||||
ide_adapter_finish_dma,
|
ide_adapter_finish_dma,
|
||||||
|
|
||||||
|
|
||||||
ide_adapter_inthand,
|
ide_adapter_inthand,
|
||||||
|
|
||||||
ide_adapter_init_channel,
|
ide_adapter_init_channel,
|
||||||
@@ -797,11 +790,7 @@ static ide_adapter_interface adapter_interface = {
|
|||||||
ide_adapter_probe_controller
|
ide_adapter_probe_controller
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if !_BUILDING_kernel && !BOOT
|
|
||||||
_EXPORT
|
|
||||||
module_info *modules[] = {
|
module_info *modules[] = {
|
||||||
&adapter_interface.info,
|
&adapter_interface.info,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Part of Open SCSI Peripheral Driver
|
Part of Open SCSI Peripheral Driver
|
||||||
@@ -128,7 +128,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
module_dependency module_dependencies[] = {
|
||||||
{ DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,11 +164,7 @@ scsi_periph_interface scsi_periph_module = {
|
|||||||
periph_get_icon
|
periph_get_icon
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if !_BUILDING_kernel && !BOOT
|
|
||||||
_EXPORT
|
|
||||||
scsi_periph_interface *modules[] = {
|
scsi_periph_interface *modules[] = {
|
||||||
&scsi_periph_module,
|
&scsi_periph_module,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -168,19 +168,19 @@ pnp_get_attr_string_nolock(device_node_handle node, const char *name,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_get_attr_raw(device_node_handle node, const char *name,
|
pnp_get_attr_raw(device_node_handle node, const char *name,
|
||||||
void **data, size_t *len, bool recursive)
|
void **data, size_t *length, bool recursive)
|
||||||
{
|
{
|
||||||
const void *orig_data;
|
const void *orig_data;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
status = pnp_get_attr_raw_nolock( node, name, &orig_data, len, recursive );
|
status = pnp_get_attr_raw_nolock( node, name, &orig_data, length, recursive );
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
void *tmp_data = malloc(*len);
|
void *tmp_data = malloc(*length);
|
||||||
if (tmp_data != NULL) {
|
if (tmp_data != NULL) {
|
||||||
memcpy(tmp_data, orig_data, *len);
|
memcpy(tmp_data, orig_data, *length);
|
||||||
*data = tmp_data;
|
*data = tmp_data;
|
||||||
} else
|
} else
|
||||||
status = B_NO_MEMORY;
|
status = B_NO_MEMORY;
|
||||||
@@ -194,18 +194,61 @@ pnp_get_attr_raw(device_node_handle node, const char *name,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
|
pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
|
||||||
const void **data, size_t *len, bool recursive)
|
const void **data, size_t *length, bool recursive)
|
||||||
{
|
{
|
||||||
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_RAW_TYPE);
|
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_RAW_TYPE);
|
||||||
if (attr == NULL)
|
if (attr == NULL)
|
||||||
return B_NAME_NOT_FOUND;
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
*data = attr->attr.value.raw.data;
|
*data = attr->attr.value.raw.data;
|
||||||
*len = attr->attr.value.raw.len;
|
*length = attr->attr.value.raw.length;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Compare two attributes for */
|
||||||
|
|
||||||
|
int
|
||||||
|
pnp_compare_attrs(const device_attr *attrA, const device_attr *attrB)
|
||||||
|
{
|
||||||
|
if (attrA->type != attrB->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (attrA->type) {
|
||||||
|
case B_UINT8_TYPE:
|
||||||
|
return (int)attrA->value.ui8 - (int)attrB->value.ui8;
|
||||||
|
|
||||||
|
case B_UINT16_TYPE:
|
||||||
|
return (int)attrA->value.ui16 - (int)attrB->value.ui16;
|
||||||
|
|
||||||
|
case B_UINT32_TYPE:
|
||||||
|
if (attrA->value.ui32 > attrB->value.ui32)
|
||||||
|
return 1;
|
||||||
|
if (attrA->value.ui32 < attrB->value.ui32)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case B_UINT64_TYPE:
|
||||||
|
if (attrA->value.ui64 > attrB->value.ui64)
|
||||||
|
return 1;
|
||||||
|
if (attrA->value.ui64 < attrB->value.ui64)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case B_STRING_TYPE:
|
||||||
|
return strcmp(attrA->value.string, attrB->value.string);
|
||||||
|
|
||||||
|
case B_RAW_TYPE:
|
||||||
|
if (attrA->value.raw.length != attrB->value.raw.length)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return memcmp(attrA->value.raw.data, attrB->value.raw.data, attrA->value.raw.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// free node attribute
|
// free node attribute
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -260,15 +303,15 @@ pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case B_RAW_TYPE:
|
case B_RAW_TYPE:
|
||||||
dest->attr.value.raw.data = malloc(src->value.raw.len);
|
dest->attr.value.raw.data = malloc(src->value.raw.length);
|
||||||
if (dest->attr.value.raw.data == NULL) {
|
if (dest->attr.value.raw.data == NULL) {
|
||||||
res = B_NO_MEMORY;
|
res = B_NO_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dest->attr.value.raw.len = src->value.raw.len;
|
dest->attr.value.raw.length = src->value.raw.length;
|
||||||
memcpy(dest->attr.value.raw.data, src->value.raw.data,
|
memcpy(dest->attr.value.raw.data, src->value.raw.data,
|
||||||
src->value.raw.len);
|
src->value.raw.length);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -448,10 +491,8 @@ static bool
|
|||||||
is_fixed_attribute(const char *name)
|
is_fixed_attribute(const char *name)
|
||||||
{
|
{
|
||||||
static const char *forbidden_list[] = {
|
static const char *forbidden_list[] = {
|
||||||
PNP_DRIVER_DRIVER, // never change driver
|
B_DRIVER_MODULE, // never change driver
|
||||||
PNP_DRIVER_TYPE, // never change type
|
|
||||||
PNP_BUS_IS_BUS, // never switch between bus/not bus mode
|
PNP_BUS_IS_BUS, // never switch between bus/not bus mode
|
||||||
PNP_DRIVER_ALWAYS_LOADED // don't confuse us by changing auto-load
|
|
||||||
};
|
};
|
||||||
uint32 i;
|
uint32 i;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
device_node_info *gNodeList;
|
device_node_info *gRootNode;
|
||||||
|
|
||||||
bool disable_useraddons;
|
bool disable_useraddons;
|
||||||
|
|
||||||
@@ -35,17 +35,13 @@ sem_id pnp_resource_wait_sem;
|
|||||||
|
|
||||||
io_resource_info *io_mem_list, *io_port_list, *isa_dma_list;
|
io_resource_info *io_mem_list, *io_port_list, *isa_dma_list;
|
||||||
|
|
||||||
#if 0
|
|
||||||
void
|
static int
|
||||||
check_settings()
|
dump_device_nodes(int argc, char **argv)
|
||||||
{
|
{
|
||||||
void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
|
dm_dump_node(gRootNode, 0);
|
||||||
|
return 0;
|
||||||
disable_useraddons = get_driver_boolean_parameter(settings, "disableuseraddons", 0, 1);
|
|
||||||
|
|
||||||
unload_driver_settings(settings);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
@@ -70,7 +66,7 @@ std_ops(int32 op, ...)
|
|||||||
|
|
||||||
device_manager_info gDeviceManagerModule = {
|
device_manager_info gDeviceManagerModule = {
|
||||||
{
|
{
|
||||||
DEVICE_MANAGER_MODULE_NAME,
|
B_DEVICE_MANAGER_MODULE_NAME,
|
||||||
0,
|
0,
|
||||||
std_ops
|
std_ops
|
||||||
},
|
},
|
||||||
@@ -78,20 +74,21 @@ device_manager_info gDeviceManagerModule = {
|
|||||||
pnp_load_driver,
|
pnp_load_driver,
|
||||||
pnp_unload_driver,
|
pnp_unload_driver,
|
||||||
|
|
||||||
pnp_rescan,
|
dm_rescan,
|
||||||
|
|
||||||
pnp_register_device,
|
dm_register_node,
|
||||||
pnp_unregister_device,
|
dm_unregister_node,
|
||||||
|
|
||||||
pnp_acquire_io_resources,
|
dm_get_next_child_node,
|
||||||
pnp_release_io_resources,
|
dm_get_parent,
|
||||||
|
dm_put_node,
|
||||||
|
|
||||||
pnp_find_device,
|
dm_acquire_io_resources,
|
||||||
|
dm_release_io_resources,
|
||||||
|
|
||||||
pnp_create_id,
|
dm_create_id,
|
||||||
pnp_free_id,
|
dm_free_id,
|
||||||
|
|
||||||
pnp_get_parent,
|
|
||||||
pnp_get_attr_uint8,
|
pnp_get_attr_uint8,
|
||||||
pnp_get_attr_uint16,
|
pnp_get_attr_uint16,
|
||||||
pnp_get_attr_uint32,
|
pnp_get_attr_uint32,
|
||||||
@@ -102,7 +99,8 @@ device_manager_info gDeviceManagerModule = {
|
|||||||
pnp_get_next_attr,
|
pnp_get_next_attr,
|
||||||
pnp_release_attr,
|
pnp_release_attr,
|
||||||
pnp_retrieve_attr,
|
pnp_retrieve_attr,
|
||||||
pnp_write_attr
|
pnp_write_attr,
|
||||||
|
NULL // remove_attr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -119,13 +117,13 @@ device_manager_init(struct kernel_args *args)
|
|||||||
|
|
||||||
TRACE(("device manager init\n"));
|
TRACE(("device manager init\n"));
|
||||||
|
|
||||||
status = id_generator_init();
|
status = dm_init_id_generator();
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
panic("could not initialize ID generator\n");
|
panic("could not initialize ID generator\n");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = nodes_init();
|
status = dm_init_nodes();
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
panic("could not initialize device nodes\n");
|
panic("could not initialize device nodes\n");
|
||||||
return status;
|
return status;
|
||||||
@@ -141,14 +139,14 @@ device_manager_init(struct kernel_args *args)
|
|||||||
io_mem_list = io_port_list = isa_dma_list = NULL;
|
io_mem_list = io_port_list = isa_dma_list = NULL;
|
||||||
pnp_fs_emulation_nesting = 0;
|
pnp_fs_emulation_nesting = 0;
|
||||||
|
|
||||||
pnp_root_init_root();
|
dm_init_root_node();
|
||||||
|
|
||||||
{
|
{
|
||||||
// dump root node
|
// dump root node
|
||||||
device_node_info *node = gNodeList;
|
device_node_info *node = gRootNode;
|
||||||
while (node && node->parent != NULL)
|
while (node && node->parent != NULL)
|
||||||
node = node->parent;
|
node = node->parent;
|
||||||
dump_device_node_info(node, 0);
|
dm_dump_node(node, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// build initial device tree; register all root bus_managers
|
// build initial device tree; register all root bus_managers
|
||||||
@@ -164,6 +162,7 @@ device_manager_init(struct kernel_args *args)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
add_debugger_command("dm_tree", &dump_device_nodes, "dump device node tree");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,17 +30,15 @@
|
|||||||
#define SYSTEM_MODULES_DIR "/boot/beos/add-ons/kernel/"
|
#define SYSTEM_MODULES_DIR "/boot/beos/add-ons/kernel/"
|
||||||
#define COMMON_MODULES_DIR "/boot/home/config/add-ons/kernel/"
|
#define COMMON_MODULES_DIR "/boot/home/config/add-ons/kernel/"
|
||||||
|
|
||||||
#define PNP_BOOT_LINKS "pnp_bootlinks"
|
|
||||||
|
|
||||||
|
|
||||||
// info about ID generator
|
// info about ID generator
|
||||||
typedef struct id_generator {
|
typedef struct id_generator {
|
||||||
struct list_link link;
|
struct list_link link;
|
||||||
struct id_generator *prev, *next;
|
struct id_generator *prev, *next;
|
||||||
int ref_count;
|
int32 ref_count;
|
||||||
char *name;
|
char *name;
|
||||||
uint32 num_ids;
|
uint32 num_ids;
|
||||||
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
|
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
|
||||||
} id_generator;
|
} id_generator;
|
||||||
|
|
||||||
|
|
||||||
@@ -60,11 +58,18 @@ typedef struct io_resource_info {
|
|||||||
} io_resource_info;
|
} io_resource_info;
|
||||||
|
|
||||||
|
|
||||||
|
// a structure to put nodes into lists
|
||||||
|
struct node_entry {
|
||||||
|
struct list_link link;
|
||||||
|
device_node_info *node;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// global lock
|
// global lock
|
||||||
// whenever you do something in terms of nodes, grab it
|
// whenever you do something in terms of nodes, grab it
|
||||||
extern benaphore gNodeLock;
|
extern benaphore gNodeLock;
|
||||||
// list of nodes (includes removed devices!)
|
// root node
|
||||||
extern device_node_info *gNodeList;
|
extern device_node_info *gRootNode;
|
||||||
|
|
||||||
// true, if user addons are disabled via safemode
|
// true, if user addons are disabled via safemode
|
||||||
extern bool disable_useraddons;
|
extern bool disable_useraddons;
|
||||||
@@ -120,6 +125,8 @@ status_t pnp_get_attr_raw(device_node_handle node, const char *name,
|
|||||||
status_t pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
|
status_t pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
|
||||||
const void **data, size_t *len, bool recursive);
|
const void **data, size_t *len, bool recursive);
|
||||||
void pnp_free_node_attr(device_attr_info *attr);
|
void pnp_free_node_attr(device_attr_info *attr);
|
||||||
|
status_t pnp_get_next_node_with_attrs(device_node_info **_node, const device_attr *attrs);
|
||||||
|
int pnp_compare_attrs(const device_attr *attrA, const device_attr *attrB);
|
||||||
status_t pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out);
|
status_t pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out);
|
||||||
status_t pnp_get_next_attr(device_node_handle node, device_attr_handle *attr);
|
status_t pnp_get_next_attr(device_node_handle node, device_attr_handle *attr);
|
||||||
status_t pnp_release_attr(device_node_handle node, device_attr_handle attr);
|
status_t pnp_release_attr(device_node_handle node, device_attr_handle attr);
|
||||||
@@ -129,62 +136,49 @@ void pnp_remove_attr_int(device_node_handle node, device_attr_info *attr);
|
|||||||
status_t pnp_remove_attr(device_node_handle node, const char *name);
|
status_t pnp_remove_attr(device_node_handle node, const char *name);
|
||||||
|
|
||||||
|
|
||||||
// boot_hack.c
|
|
||||||
#if 0
|
|
||||||
void pnp_load_boot_links( void );
|
|
||||||
void pnp_unload_boot_links( void );
|
|
||||||
char *pnp_boot_safe_realpath(
|
|
||||||
const char *file_name, char *resolved_path );
|
|
||||||
int pnp_boot_safe_lstat( const char *file_name, struct stat *info );
|
|
||||||
DIR *pnp_boot_safe_opendir( const char *dirname );
|
|
||||||
int pnp_boot_safe_closedir( DIR *dirp );
|
|
||||||
struct dirent *pnp_boot_safe_readdir( DIR *dirp );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// driver_loader.c
|
// driver_loader.c
|
||||||
|
|
||||||
status_t pnp_load_driver(device_node_handle node, void *user_cookie,
|
status_t pnp_load_driver(device_node_handle node, void *user_cookie,
|
||||||
driver_module_info **interface, void **cookie);
|
driver_module_info **interface, void **cookie);
|
||||||
status_t pnp_unload_driver(device_node_handle node);
|
status_t pnp_unload_driver(device_node_handle node);
|
||||||
void pnp_unblock_load(device_node_info *node);
|
void pnp_unblock_load(device_node_info *node);
|
||||||
void pnp_load_driver_automatically(device_node_info *node, bool after_rescan);
|
|
||||||
void pnp_unload_driver_automatically(device_node_info *node, bool before_rescan);
|
|
||||||
|
|
||||||
|
|
||||||
// id_generator.c
|
// id_generator.c
|
||||||
|
|
||||||
int32 pnp_create_id(const char *name);
|
int32 dm_create_id(const char *name);
|
||||||
status_t pnp_free_id(const char *name, uint32 id);
|
status_t dm_free_id(const char *name, uint32 id);
|
||||||
extern status_t id_generator_init(void);
|
extern status_t dm_init_id_generator(void);
|
||||||
|
|
||||||
|
|
||||||
// io_resources.c
|
// io_resources.c
|
||||||
|
|
||||||
status_t pnp_acquire_io_resources(io_resource *resources, io_resource_handle *handles);
|
status_t dm_acquire_io_resources(io_resource *resources, io_resource_handle *handles);
|
||||||
status_t pnp_release_io_resources(const io_resource_handle *handles);
|
status_t dm_release_io_resources(const io_resource_handle *handles);
|
||||||
void pnp_assign_io_resources(device_node_info *node, const io_resource_handle *handles);
|
void dm_assign_io_resources(device_node_info *node, const io_resource_handle *handles);
|
||||||
void pnp_release_node_resources(device_node_info *node);
|
void dm_release_node_resources(device_node_info *node);
|
||||||
|
|
||||||
|
|
||||||
// nodes.c
|
// nodes.c
|
||||||
|
|
||||||
status_t pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
|
status_t dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
|
||||||
device_node_info **new_node);
|
device_node_info **new_node);
|
||||||
void pnp_create_node_links(device_node_info *node, device_node_info *parent);
|
void dm_add_child_node(device_node_info *node, device_node_info *parent);
|
||||||
void pnp_add_node_ref(device_node_info *node);
|
void dm_get_node_nolock(device_node_info *node);
|
||||||
void pnp_remove_node_ref(device_node_info *node);
|
void dm_get_node(device_node_info *node);
|
||||||
void pnp_remove_node_ref_nolock(device_node_info *node);
|
void dm_put_node_nolock(device_node_info *node);
|
||||||
device_node_handle pnp_find_device(device_node_handle parent, const device_attr *attrs);
|
void dm_dump_node(device_node_info *node, int32 level);
|
||||||
device_node_handle pnp_get_parent(device_node_handle node);
|
status_t dm_init_nodes(void);
|
||||||
void dump_device_node_info(device_node_info *node, int32 level);
|
|
||||||
extern status_t nodes_init(void);
|
void dm_put_node(device_node_info *node);
|
||||||
|
status_t dm_get_next_child_node(device_node_info *parent,
|
||||||
|
device_node_info **_node, const device_attr *attrs);
|
||||||
|
device_node_info *dm_get_parent(device_node_info *node);
|
||||||
|
|
||||||
|
|
||||||
// notifications.c
|
// notifications.c
|
||||||
|
|
||||||
status_t pnp_notify_probe_by_module(device_node_info *node,
|
status_t dm_notify_unregistration(device_node_info *node);
|
||||||
const char *consumer_name);
|
|
||||||
void pnp_notify_unregistration(device_node_info *notify_list);
|
|
||||||
void pnp_start_hook_call(device_node_info *node);
|
void pnp_start_hook_call(device_node_info *node);
|
||||||
void pnp_start_hook_call_nolock(device_node_info *node);
|
void pnp_start_hook_call_nolock(device_node_info *node);
|
||||||
void pnp_finish_hook_call(device_node_info *node);
|
void pnp_finish_hook_call(device_node_info *node);
|
||||||
@@ -199,35 +193,30 @@ status_t pnp_expand_pattern_attr(device_node_info *node, const char *attr_name,
|
|||||||
char **expanded);
|
char **expanded);
|
||||||
|
|
||||||
|
|
||||||
// probe.c
|
// probe.cpp
|
||||||
status_t pnp_notify_fixed_consumers(device_node_handle node);
|
status_t dm_register_child_device(device_node_info *node, const char *childName);
|
||||||
status_t pnp_notify_dynamic_consumers(device_node_info *node);
|
status_t dm_register_fixed_child_devices(device_node_info *node);
|
||||||
|
status_t dm_register_dynamic_child_devices(device_node_info *node);
|
||||||
|
|
||||||
|
|
||||||
// registration.c
|
// registration.c
|
||||||
|
|
||||||
status_t pnp_register_device(device_node_handle parent, const device_attr *attrs,
|
status_t dm_register_node(device_node_handle parent, const device_attr *attrs,
|
||||||
const io_resource_handle *resources, device_node_handle *node);
|
const io_resource_handle *resources, device_node_handle *_newNode);
|
||||||
status_t pnp_unregister_device(device_node_handle node);
|
status_t dm_unregister_node(device_node_handle node);
|
||||||
void pnp_unregister_node_rec(device_node_info *node, device_node_info **dependency_list);
|
|
||||||
void pnp_unref_unregistered_nodes(device_node_info *node_list);
|
void pnp_unref_unregistered_nodes(device_node_info *node_list);
|
||||||
void pnp_defer_probing_of_children_nolock(device_node_info *node);
|
|
||||||
void pnp_defer_probing_of_children(device_node_info *node);
|
|
||||||
void pnp_probe_waiting_children_nolock(device_node_info *node);
|
|
||||||
void pnp_probe_waiting_children(device_node_info *node);
|
|
||||||
|
|
||||||
// root_node.c
|
// root_node.c
|
||||||
|
|
||||||
extern void pnp_root_init_root(void);
|
void dm_init_root_node(void);
|
||||||
extern void pnp_root_destroy_root(void);
|
|
||||||
extern void pnp_root_rescan_root(void);
|
|
||||||
|
|
||||||
// scan.c
|
// scan.c
|
||||||
|
|
||||||
status_t pnp_rescan(device_node_handle node, uint32 depth);
|
status_t dm_rescan(device_node_handle node);
|
||||||
status_t pnp_rescan_int(device_node_info *node, uint32 depth,
|
status_t dm_register_child_devices(device_node_info *node);
|
||||||
bool ignore_fixed_consumers);
|
|
||||||
status_t pnp_initial_scan(device_node_info *node);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,103 +69,6 @@ pnp_wait_load_block(device_node_info *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** load driver automatically after registration/rescan of node. */
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_load_driver_automatically(device_node_info *node, bool after_rescan)
|
|
||||||
{
|
|
||||||
uint8 always_loaded;
|
|
||||||
status_t res;
|
|
||||||
driver_module_info *interface;
|
|
||||||
void *cookie;
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
// ignore dead nodes
|
|
||||||
if (!node->registered)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (node->automatically_loaded)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (pnp_get_attr_uint8_nolock(node, PNP_DRIVER_ALWAYS_LOADED,
|
|
||||||
&always_loaded, false ) != B_OK)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (always_loaded < 1 || always_loaded > 2)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// this test is probably useless as the driver would be kept loaded
|
|
||||||
// during rescan anyway
|
|
||||||
if (always_loaded == 2 && after_rescan)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// alright - time to get the driver loaded
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
res = pnp_load_driver(node, NULL, &interface, &cookie);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
// if driver cannot be loaded, we don't really care
|
|
||||||
if (res == B_OK )
|
|
||||||
node->automatically_loaded = true;
|
|
||||||
else
|
|
||||||
dprintf("driver could not be automatically loaded\n");
|
|
||||||
|
|
||||||
err:
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** unload driver that got loaded automatically. */
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_unload_driver_automatically(device_node_info *node, bool before_rescan)
|
|
||||||
{
|
|
||||||
uint8 always_loaded;
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
if (!node->automatically_loaded)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (pnp_get_attr_uint8_nolock(node, PNP_DRIVER_ALWAYS_LOADED,
|
|
||||||
&always_loaded, false) != B_OK)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// this test is probably useless as the driver wouldn't be
|
|
||||||
// loaded anyway
|
|
||||||
if (always_loaded < 1 || always_loaded > 2)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (always_loaded == 2 && before_rescan)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// time to unload the driver
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
res = pnp_unload_driver(node);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
// don't reset flag if unloading failed;
|
|
||||||
// if this happens during unregistration, this won't help;
|
|
||||||
// but if this happens during rescan, the driver only stays
|
|
||||||
// loaded during rescan, which can be handled
|
|
||||||
if (res == B_OK)
|
|
||||||
node->automatically_loaded = false;
|
|
||||||
else
|
|
||||||
dprintf("driver could not be unloaded during scan\n");
|
|
||||||
|
|
||||||
err:
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** load driver for real
|
/** load driver for real
|
||||||
* (loader_lock must be hold)
|
* (loader_lock must be hold)
|
||||||
*/
|
*/
|
||||||
@@ -173,49 +76,48 @@ err:
|
|||||||
static status_t
|
static status_t
|
||||||
load_driver_int(device_node_info *node, void *user_cookie)
|
load_driver_int(device_node_info *node, void *user_cookie)
|
||||||
{
|
{
|
||||||
char *module_name;
|
|
||||||
driver_module_info *driver;
|
driver_module_info *driver;
|
||||||
|
char *moduleName;
|
||||||
void *cookie;
|
void *cookie;
|
||||||
status_t res;
|
status_t status;
|
||||||
|
|
||||||
TRACE(("load_driver_int()\n"));
|
TRACE(("load_driver_int()\n"));
|
||||||
|
|
||||||
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false);
|
status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
|
||||||
if (res != B_OK)
|
if (status != B_OK)
|
||||||
return res;
|
return status;
|
||||||
|
|
||||||
TRACE(("%s\n", module_name));
|
TRACE(("%s\n", moduleName));
|
||||||
|
|
||||||
res = get_module(module_name, (module_info **)&driver);
|
status = get_module(moduleName, (module_info **)&driver);
|
||||||
if (res < B_OK) {
|
if (status < B_OK) {
|
||||||
dprintf("Cannot load module %s\n", module_name);
|
dprintf("Cannot load module %s\n", moduleName);
|
||||||
goto err;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (driver->init_device == NULL) {
|
if (driver->init_driver == NULL) {
|
||||||
dprintf("Driver %s has no init_device hook\n", module_name);
|
dprintf("Driver %s has no init_driver hook\n", moduleName);
|
||||||
res = B_ERROR;
|
status = B_ERROR;
|
||||||
goto err2;
|
goto err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = driver->init_device(node, user_cookie, &cookie);
|
status = driver->init_driver(node, user_cookie, &cookie);
|
||||||
if (res < B_OK) {
|
if (status < B_OK) {
|
||||||
dprintf("init device failed (node %p, %s): %s\n", node, module_name, strerror(res));
|
dprintf("init driver failed (node %p, %s): %s\n", node, moduleName, strerror(status));
|
||||||
goto err2;
|
goto err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->driver = driver;
|
node->driver = driver;
|
||||||
node->cookie = cookie;
|
node->cookie = cookie;
|
||||||
|
|
||||||
free(module_name);
|
free(moduleName);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
put_module(module_name);
|
put_module(moduleName);
|
||||||
|
err1:
|
||||||
err:
|
free(moduleName);
|
||||||
free(module_name);
|
return status;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -257,12 +159,6 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
|
|||||||
// make sure noone else load/unloads/notifies the driver
|
// make sure noone else load/unloads/notifies the driver
|
||||||
pnp_start_hook_call_nolock(node);
|
pnp_start_hook_call_nolock(node);
|
||||||
|
|
||||||
// during load, driver may register children;
|
|
||||||
// probing them for consumers may be impossible as they
|
|
||||||
// may try to load driver -> deadlock
|
|
||||||
// so we block probing for consumers of children
|
|
||||||
pnp_defer_probing_of_children_nolock(node);
|
|
||||||
|
|
||||||
if (!node->registered) {
|
if (!node->registered) {
|
||||||
// device got lost meanwhile
|
// device got lost meanwhile
|
||||||
TRACE(("Device got lost during wait\n"));
|
TRACE(("Device got lost during wait\n"));
|
||||||
@@ -296,16 +192,11 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
|
|||||||
if (res == B_OK) {
|
if (res == B_OK) {
|
||||||
// everything went fine - increase load counter
|
// everything went fine - increase load counter
|
||||||
++node->load_count;
|
++node->load_count;
|
||||||
|
|
||||||
// now we can safely probe for consumers of children as the
|
|
||||||
// driver is fully loaded
|
|
||||||
pnp_probe_waiting_children_nolock(node);
|
|
||||||
} else {
|
} else {
|
||||||
// loading failed or device got removed - restore reference count;
|
// loading failed or device got removed - restore reference count;
|
||||||
// but first (i.e. as long as ref_count is increased) get
|
// but first (i.e. as long as ref_count is increased) get
|
||||||
// rid of waiting children
|
// rid of waiting children
|
||||||
pnp_probe_waiting_children_nolock(node);
|
dm_put_node_nolock(node);
|
||||||
pnp_remove_node_ref_nolock(node);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// driver is already loaded, so increase load_count
|
// driver is already loaded, so increase load_count
|
||||||
@@ -323,7 +214,7 @@ pnp_load_driver(device_node_handle node, void *user_cookie,
|
|||||||
*cookie = node->cookie;
|
*cookie = node->cookie;
|
||||||
|
|
||||||
TRACE(("load_driver: Success \"%s\"\n",
|
TRACE(("load_driver: Success \"%s\"\n",
|
||||||
((struct module_info *)(*interface))->name));
|
((struct module_info *)node->driver)->name));
|
||||||
} else {
|
} else {
|
||||||
TRACE(("load_driver: Failure (%s)\n", strerror(res)));
|
TRACE(("load_driver: Failure (%s)\n", strerror(res)));
|
||||||
}
|
}
|
||||||
@@ -338,26 +229,26 @@ static status_t
|
|||||||
unload_driver_int(device_node_info *node)
|
unload_driver_int(device_node_info *node)
|
||||||
{
|
{
|
||||||
driver_module_info *driver = node->driver;
|
driver_module_info *driver = node->driver;
|
||||||
char *module_name;
|
char *moduleName;
|
||||||
status_t res;
|
status_t status;
|
||||||
|
|
||||||
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false);
|
status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
|
||||||
if (res != B_OK)
|
if (status != B_OK)
|
||||||
return res;
|
return status;
|
||||||
|
|
||||||
TRACE(("unload_driver_int: %s\n", module_name));
|
TRACE(("unload_driver_int: %s\n", moduleName));
|
||||||
|
|
||||||
if (driver->uninit_device == NULL) {
|
if (driver->uninit_driver == NULL) {
|
||||||
// it has no uninit - we can't unload it, so it stays in memory forever
|
// it has no uninit - we can't unload it, so it stays in memory forever
|
||||||
TRACE(("Driver %s has no uninit_device hook\n", module_name));
|
TRACE(("Driver %s has no uninit_device hook\n", moduleName));
|
||||||
res = B_ERROR;
|
status = B_ERROR;
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = driver->uninit_device(node->cookie);
|
status = driver->uninit_driver(node->cookie);
|
||||||
if (res != B_OK) {
|
if (status != B_OK) {
|
||||||
TRACE(("Failed to uninit driver %s (%s)\n", module_name, strerror(res)));
|
TRACE(("Failed to uninit driver %s (%s)\n", moduleName, strerror(status)));
|
||||||
goto err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it was unregistered a while ago but couldn't get cleaned up
|
// if it was unregistered a while ago but couldn't get cleaned up
|
||||||
@@ -367,14 +258,11 @@ unload_driver_int(device_node_info *node)
|
|||||||
driver->device_cleanup(node);
|
driver->device_cleanup(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
put_module(module_name);
|
put_module(moduleName);
|
||||||
|
|
||||||
free(module_name);
|
out:
|
||||||
return B_OK;
|
free(moduleName);
|
||||||
|
return status;
|
||||||
err:
|
|
||||||
free(module_name);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -428,7 +316,7 @@ pnp_unload_driver(device_node_handle node)
|
|||||||
// everything is fine, so decrease load_count ...
|
// everything is fine, so decrease load_count ...
|
||||||
--node->load_count;
|
--node->load_count;
|
||||||
// ... and reference count
|
// ... and reference count
|
||||||
pnp_remove_node_ref_nolock(node);
|
dm_put_node_nolock(node);
|
||||||
} else {
|
} else {
|
||||||
// unloading failed: leave loaded in memory forever
|
// unloading failed: leave loaded in memory forever
|
||||||
// as load_count is not decreased, the driver will never
|
// as load_count is not decreased, the driver will never
|
||||||
@@ -443,7 +331,7 @@ pnp_unload_driver(device_node_handle node)
|
|||||||
// no concurrent load/unload and load_count won't reach zero
|
// no concurrent load/unload and load_count won't reach zero
|
||||||
--node->load_count;
|
--node->load_count;
|
||||||
// each load increased reference count by one - time to undo that
|
// each load increased reference count by one - time to undo that
|
||||||
pnp_remove_node_ref_nolock(node);
|
dm_put_node_nolock(node);
|
||||||
|
|
||||||
res = B_OK;
|
res = B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ release_generator(id_generator *generator)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
id_generator_init(void)
|
dm_init_id_generator(void)
|
||||||
{
|
{
|
||||||
list_init(&sGenerators);
|
list_init(&sGenerators);
|
||||||
return benaphore_init(&sGeneratorLock, "id generator");
|
return benaphore_init(&sGeneratorLock, "id generator");
|
||||||
@@ -167,13 +167,13 @@ id_generator_init(void)
|
|||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
// Public API
|
// Public module API
|
||||||
|
|
||||||
|
|
||||||
/** Create automatic ID */
|
/** Create automatic ID */
|
||||||
|
|
||||||
int32
|
int32
|
||||||
pnp_create_id(const char *name)
|
dm_create_id(const char *name)
|
||||||
{
|
{
|
||||||
id_generator *generator;
|
id_generator *generator;
|
||||||
int32 id;
|
int32 id;
|
||||||
@@ -203,7 +203,7 @@ pnp_create_id(const char *name)
|
|||||||
/** Free automatically generated ID */
|
/** Free automatically generated ID */
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_free_id(const char *name, uint32 id)
|
dm_free_id(const char *name, uint32 id)
|
||||||
{
|
{
|
||||||
id_generator *generator;
|
id_generator *generator;
|
||||||
|
|
||||||
|
|||||||
@@ -67,17 +67,17 @@ validate_io_resource(io_resource *src)
|
|||||||
|
|
||||||
switch (src->type) {
|
switch (src->type) {
|
||||||
case IO_MEM:
|
case IO_MEM:
|
||||||
if (src->base + src->len < src->base)
|
if (src->base + src->length < src->base)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
break;
|
break;
|
||||||
case IO_PORT:
|
case IO_PORT:
|
||||||
if ((uint16)src->base != src->base
|
if ((uint16)src->base != src->base
|
||||||
|| (uint16)src->len != src->len
|
|| (uint16)src->length != src->length
|
||||||
|| (uint16)(src->base + src->len) < src->base)
|
|| (uint16)(src->base + src->length) < src->base)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
break;
|
break;
|
||||||
case ISA_DMA_CHANNEL:
|
case ISA_DMA_CHANNEL:
|
||||||
if (src->base > 8 || src->len != 1)
|
if (src->base > 8 || src->length != 1)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ alloc_io_resource_info(io_resource *src, io_resource_info **dest_out)
|
|||||||
|
|
||||||
dest->resource.type = src->type;
|
dest->resource.type = src->type;
|
||||||
dest->resource.base = src->base;
|
dest->resource.base = src->base;
|
||||||
dest->resource.len = src->len;
|
dest->resource.length = src->length;
|
||||||
|
|
||||||
*dest_out = dest;
|
*dest_out = dest;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -123,15 +123,15 @@ acquire_range(io_resource_info **list, io_resource_info *resource)
|
|||||||
{
|
{
|
||||||
io_resource_info *cur;
|
io_resource_info *cur;
|
||||||
uint32 base = resource->resource.base;
|
uint32 base = resource->resource.base;
|
||||||
uint32 len = resource->resource.len;
|
uint32 length = resource->resource.length;
|
||||||
status_t res = B_OK;
|
status_t res = B_OK;
|
||||||
|
|
||||||
TRACE(("acquire_range(base %lx, len %lx)\n", base, len));
|
TRACE(("acquire_range(base %lx, length %lx)\n", base, length));
|
||||||
|
|
||||||
for (cur = *list; cur != NULL; cur = cur->next) {
|
for (cur = *list; cur != NULL; cur = cur->next) {
|
||||||
// we need the "base + len - 1" trick to avoid wrap around at 4 GB
|
// we need the "base + length - 1" trick to avoid wrap around at 4 GB
|
||||||
if (cur->resource.base >= base
|
if (cur->resource.base >= base
|
||||||
&& cur->resource.base + len - 1 <= base + len - 1) {
|
&& cur->resource.base + length - 1 <= base + length - 1) {
|
||||||
device_node_info *owner = cur->owner;
|
device_node_info *owner = cur->owner;
|
||||||
|
|
||||||
TRACE(("collision\n"));
|
TRACE(("collision\n"));
|
||||||
@@ -180,18 +180,19 @@ acquire_range(io_resource_info **list, io_resource_info *resource)
|
|||||||
static void
|
static void
|
||||||
free_io_resource_info(io_resource_info *resource)
|
free_io_resource_info(io_resource_info *resource)
|
||||||
{
|
{
|
||||||
TRACE(("free_io_resource_info"));
|
TRACE(("free_io_resource_info()\n"));
|
||||||
|
|
||||||
free(resource);
|
free(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// acquire I/O resource
|
/** Acquire I/O resource.
|
||||||
// a I/O resource info structure is allocated and added to
|
* An I/O resource info structure is allocated and added to
|
||||||
// appropriate resource list (i.e. mem/port/channel) plus
|
* appropriate resource list (i.e. mem/port/channel) plus
|
||||||
// all colliding resources (including ours) are marked blocked;
|
* all colliding resources (including ours) are marked blocked;
|
||||||
// returns B_WOULD_BLOCK on collision with temporary allocation;
|
* returns B_WOULD_BLOCK on collision with temporary allocation;
|
||||||
// node_lock must be hold
|
* gNodeLock must be hold.
|
||||||
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
acquire_io_resource(io_resource *src, io_resource_handle *dest_out)
|
acquire_io_resource(io_resource *src, io_resource_handle *dest_out)
|
||||||
@@ -199,7 +200,8 @@ acquire_io_resource(io_resource *src, io_resource_handle *dest_out)
|
|||||||
io_resource_info *dest;
|
io_resource_info *dest;
|
||||||
status_t res;
|
status_t res;
|
||||||
|
|
||||||
TRACE(("acquire_io_resource(type=%ld, base=%lx, len=%lx)\n", src->type, src->base, src->len));
|
TRACE(("acquire_io_resource(type = %ld, base = %lx, length = %lx)\n",
|
||||||
|
src->type, src->base, src->length));
|
||||||
|
|
||||||
res = validate_io_resource(src);
|
res = validate_io_resource(src);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
@@ -273,7 +275,7 @@ release_range(io_resource_info **list, io_resource_info *resource, io_resource_i
|
|||||||
{
|
{
|
||||||
io_resource_info *cur;
|
io_resource_info *cur;
|
||||||
uint32 base = resource->resource.base;
|
uint32 base = resource->resource.base;
|
||||||
uint32 len = resource->resource.len;
|
uint32 length = resource->resource.length;
|
||||||
|
|
||||||
TRACE(("release_range()\n"));
|
TRACE(("release_range()\n"));
|
||||||
|
|
||||||
@@ -282,8 +284,8 @@ release_range(io_resource_info **list, io_resource_info *resource, io_resource_i
|
|||||||
// ignore ourselves
|
// ignore ourselves
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we need the "base + len - 1" trick to avoid wrap around at 4 GB
|
// we need the "base + length - 1" trick to avoid wrap around at 4 GB
|
||||||
if (cur->resource.base >= base && cur->resource.base + len - 1 <= base + len - 1) {
|
if (cur->resource.base >= base && cur->resource.base + length - 1 <= base + length - 1) {
|
||||||
device_node_info *owner = cur->owner;
|
device_node_info *owner = cur->owner;
|
||||||
|
|
||||||
TRACE(("unblock\n"));
|
TRACE(("unblock\n"));
|
||||||
@@ -391,46 +393,6 @@ status_t acquire_io_resources(io_resource *resources, io_resource_handle *handle
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public: acquire I/O resources
|
|
||||||
|
|
||||||
status_t
|
|
||||||
pnp_acquire_io_resources(io_resource *resources, io_resource_handle *handles)
|
|
||||||
{
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
TRACE(("pnp_acquire_io_resources()\n"));
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
res = acquire_io_resources(resources, handles);
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
TRACE(("done (%s)", strerror(res)));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// public: release I/O resources
|
|
||||||
|
|
||||||
status_t
|
|
||||||
pnp_release_io_resources(const io_resource_handle *handles)
|
|
||||||
{
|
|
||||||
io_resource_info *const *resource;
|
|
||||||
|
|
||||||
if (handles == NULL)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
for (resource = handles; *resource != NULL; ++resource)
|
|
||||||
release_io_resource(*resource);
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// unregister devices that collide with one of our I/O resources
|
// unregister devices that collide with one of our I/O resources
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -461,7 +423,7 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
|
|||||||
{
|
{
|
||||||
io_resource_info *cur;
|
io_resource_info *cur;
|
||||||
uint32 base = resource->resource.base;
|
uint32 base = resource->resource.base;
|
||||||
uint32 len = resource->resource.len;
|
uint32 length = resource->resource.length;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for (cur = list; cur != NULL; cur = cur->next) {
|
for (cur = list; cur != NULL; cur = cur->next) {
|
||||||
@@ -469,9 +431,9 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
|
|||||||
if (cur == resource)
|
if (cur == resource)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we need the "base + len - 1" trick to avoid wrap around at 4 GB
|
// we need the "base + length - 1" trick to avoid wrap around at 4 GB
|
||||||
if (cur->resource.base >= base
|
if (cur->resource.base >= base
|
||||||
&& cur->resource.base + len - 1 <= base + len - 1) {
|
&& cur->resource.base + length - 1 <= base + length - 1) {
|
||||||
device_node_handle owner = cur->owner;
|
device_node_handle owner = cur->owner;
|
||||||
|
|
||||||
if (owner == NULL)
|
if (owner == NULL)
|
||||||
@@ -487,11 +449,11 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
|
|||||||
|
|
||||||
// unregister device node - we own its resources now
|
// unregister device node - we own its resources now
|
||||||
// (its resources are freed by the next remove_node_ref call)
|
// (its resources are freed by the next remove_node_ref call)
|
||||||
pnp_unregister_device(owner);
|
dm_unregister_node(owner);
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
pnp_remove_node_ref_nolock(owner);
|
dm_put_node_nolock(owner);
|
||||||
// restart loop as resource list may have changed meanwhile
|
// restart loop as resource list may have changed meanwhile
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -500,11 +462,31 @@ unregister_colliding_node_range(io_resource_info *list, io_resource_info *resour
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// transfer temporary I/O resources to device node;
|
/** unblock other temporary allocations so they can retry
|
||||||
// colliding devices are unregistered
|
* gNodeLock must be hold
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
unblock_temporary_allocation(void)
|
||||||
|
{
|
||||||
|
if (pnp_resource_wait_count > 0) {
|
||||||
|
TRACE(("unblock concurrent temporary allocation\n"));
|
||||||
|
|
||||||
|
release_sem_etc(pnp_resource_wait_sem, pnp_resource_wait_count, 0);
|
||||||
|
pnp_resource_wait_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
/** transfer temporary I/O resources to device node;
|
||||||
|
* colliding devices are unregistered
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
pnp_assign_io_resources(device_node_info *node, const io_resource_handle *resources)
|
dm_assign_io_resources(device_node_info *node, const io_resource_handle *resources)
|
||||||
{
|
{
|
||||||
io_resource_handle *resource;
|
io_resource_handle *resource;
|
||||||
|
|
||||||
@@ -531,27 +513,13 @@ pnp_assign_io_resources(device_node_info *node, const io_resource_handle *resour
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// unblock other temporary allocations so they can retry
|
/** release I/O resources of a device node and set list to NULL;
|
||||||
// node_lock must be hold
|
* users previously blocked by our resource alloction are notified;
|
||||||
|
* gNodeLock must be hold
|
||||||
static void
|
*/
|
||||||
unblock_temporary_allocation(void)
|
|
||||||
{
|
|
||||||
if (pnp_resource_wait_count > 0) {
|
|
||||||
TRACE(("unblock concurrent temporary allocation\n"));
|
|
||||||
|
|
||||||
release_sem_etc(pnp_resource_wait_sem, pnp_resource_wait_count, 0);
|
|
||||||
pnp_resource_wait_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// release I/O resources of a device node and set list to NULL;
|
|
||||||
// users previously blocked by our resource alloction are notified;
|
|
||||||
// node_lock must be hold
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pnp_release_node_resources(device_node_info *node)
|
dm_release_node_resources(device_node_info *node)
|
||||||
{
|
{
|
||||||
io_resource_handle *resource;
|
io_resource_handle *resource;
|
||||||
|
|
||||||
@@ -568,3 +536,47 @@ pnp_release_node_resources(device_node_info *node)
|
|||||||
*node->io_resources = NULL;
|
*node->io_resources = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
// Part of the module API
|
||||||
|
|
||||||
|
|
||||||
|
/** acquire I/O resources */
|
||||||
|
|
||||||
|
status_t
|
||||||
|
dm_acquire_io_resources(io_resource *resources, io_resource_handle *handles)
|
||||||
|
{
|
||||||
|
status_t res;
|
||||||
|
|
||||||
|
TRACE(("pnp_acquire_io_resources()\n"));
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
res = acquire_io_resources(resources, handles);
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
|
TRACE(("done (%s)", strerror(res)));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** release I/O resources */
|
||||||
|
|
||||||
|
status_t
|
||||||
|
dm_release_io_resources(const io_resource_handle *handles)
|
||||||
|
{
|
||||||
|
io_resource_info *const *resource;
|
||||||
|
|
||||||
|
if (handles == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
|
for (resource = handles; *resource != NULL; ++resource)
|
||||||
|
release_io_resource(*resource);
|
||||||
|
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,24 +42,50 @@
|
|||||||
benaphore gNodeLock;
|
benaphore gNodeLock;
|
||||||
|
|
||||||
|
|
||||||
// increase ref_count of node
|
static void
|
||||||
|
put_level(int32 level)
|
||||||
void
|
|
||||||
pnp_add_node_ref(device_node_info *node)
|
|
||||||
{
|
{
|
||||||
TRACE(("add_node_ref(%p)\n", node));
|
while (level-- > 0)
|
||||||
|
dprintf(" ");
|
||||||
if (node == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
node->ref_count++;
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// free attributes of node
|
static void
|
||||||
// if an attribute is still in use, it's deletion is postponed
|
dump_attribute(device_attr_info *attr, int32 level)
|
||||||
|
{
|
||||||
|
if (attr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
put_level(level + 2);
|
||||||
|
dprintf("\"%s\" : ", attr->attr.name);
|
||||||
|
switch (attr->attr.type) {
|
||||||
|
case B_STRING_TYPE:
|
||||||
|
dprintf("string : \"%s\"", attr->attr.value.string);
|
||||||
|
break;
|
||||||
|
case B_UINT8_TYPE:
|
||||||
|
dprintf("uint8 : %u (%#x)", attr->attr.value.ui8, attr->attr.value.ui8);
|
||||||
|
break;
|
||||||
|
case B_UINT16_TYPE:
|
||||||
|
dprintf("uint16 : %u (%#x)", attr->attr.value.ui16, attr->attr.value.ui16);
|
||||||
|
break;
|
||||||
|
case B_UINT32_TYPE:
|
||||||
|
dprintf("uint32 : %lu (%#lx)", attr->attr.value.ui32, attr->attr.value.ui32);
|
||||||
|
break;
|
||||||
|
case B_UINT64_TYPE:
|
||||||
|
dprintf("uint64 : %Lu (%#Lx)", attr->attr.value.ui64, attr->attr.value.ui64);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintf("raw data");
|
||||||
|
}
|
||||||
|
dprintf("\n");
|
||||||
|
|
||||||
|
dump_attribute(attr->next, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** free attributes of node
|
||||||
|
* if an attribute is still in use, it's deletion is postponed
|
||||||
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_node_attrs(device_node_info *node)
|
free_node_attrs(device_node_info *node)
|
||||||
@@ -93,16 +119,14 @@ free_node_resources(device_node_info *node)
|
|||||||
static void
|
static void
|
||||||
free_node(device_node_info *node)
|
free_node(device_node_info *node)
|
||||||
{
|
{
|
||||||
const char *generator_name, *driver_name, *type;
|
const char *generator_name, *driver_name;
|
||||||
uint32 auto_id;
|
uint32 auto_id;
|
||||||
|
|
||||||
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK)
|
// ToDo: we lose memory here if the attributes are available!
|
||||||
|
if (pnp_get_attr_string_nolock(node, B_DRIVER_MODULE, &driver_name, false) != B_OK)
|
||||||
driver_name = "?";
|
driver_name = "?";
|
||||||
|
|
||||||
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_TYPE, &type, false) != B_OK)
|
TRACE(("free_node(node: %p, driver: %s)\n", node, driver_name));
|
||||||
type = "?";
|
|
||||||
|
|
||||||
TRACE(("free_node(node: %p, driver: %s, type: %s)\n", node, driver_name, type));
|
|
||||||
|
|
||||||
// free associated auto ID, if requested
|
// free associated auto ID, if requested
|
||||||
if (pnp_get_attr_string_nolock(node, PNP_MANAGER_ID_GENERATOR,
|
if (pnp_get_attr_string_nolock(node, PNP_MANAGER_ID_GENERATOR,
|
||||||
@@ -110,13 +134,10 @@ free_node(device_node_info *node)
|
|||||||
if (pnp_get_attr_uint32(node, PNP_MANAGER_AUTO_ID, &auto_id, false) != B_OK) {
|
if (pnp_get_attr_uint32(node, PNP_MANAGER_AUTO_ID, &auto_id, false) != B_OK) {
|
||||||
TRACE(("Cannot find corresponding auto_id of generator %s", generator_name));
|
TRACE(("Cannot find corresponding auto_id of generator %s", generator_name));
|
||||||
} else
|
} else
|
||||||
pnp_free_id(generator_name, auto_id);
|
dm_free_id(generator_name, auto_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pnp_release_node_resources(node);
|
dm_release_node_resources(node);
|
||||||
|
|
||||||
//list_remove_link(node);
|
|
||||||
REMOVE_DL_LIST( node, gNodeList, );
|
|
||||||
|
|
||||||
delete_sem(node->hook_sem);
|
delete_sem(node->hook_sem);
|
||||||
delete_sem(node->load_block_sem);
|
delete_sem(node->load_block_sem);
|
||||||
@@ -127,55 +148,6 @@ free_node(device_node_info *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remove node reference and clean it up if necessary
|
|
||||||
// (node_lock must be hold)
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_remove_node_ref_nolock(device_node_info *node)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
device_node_info *parent;
|
|
||||||
|
|
||||||
TRACE(("pnp_remove_node_ref_internal(ref_count of %p: %ld)\n", node, node->ref_count - 1));
|
|
||||||
|
|
||||||
// unregistered devices loose their I/O resources as soon as they
|
|
||||||
// are unloaded
|
|
||||||
if (!node->registered && node->loading == 0 && node->load_count == 0)
|
|
||||||
pnp_release_node_resources(node);
|
|
||||||
|
|
||||||
if (--node->ref_count > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TRACE(("cleaning up %p (parent: %p)\n", node, node->parent));
|
|
||||||
|
|
||||||
// time to clean up
|
|
||||||
parent = node->parent;
|
|
||||||
|
|
||||||
if (parent != NULL)
|
|
||||||
// list_remove_item(&parent->children, node);
|
|
||||||
REMOVE_DL_LIST(node, parent->children, siblings_ );
|
|
||||||
|
|
||||||
free_node(node);
|
|
||||||
|
|
||||||
// unrolled recursive call: decrease ref_count of parent as well
|
|
||||||
node = parent;
|
|
||||||
} while (node != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// remove node reference and clean it up if necessary
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_remove_node_ref(device_node_info *node)
|
|
||||||
{
|
|
||||||
TRACE(("pnp_remove_node_ref(%p)\n", node));
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
pnp_remove_node_ref_nolock(node);
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// copy node attributes into node's attribute list
|
// copy node attributes into node's attribute list
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
@@ -237,18 +209,21 @@ allocate_node_resource_array(device_node_info *node, const io_resource_handle *r
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// allocate device node info structure;
|
// #pragma mark -
|
||||||
// initially, ref_count is one to make sure node won't get destroyed by mistake
|
// Device Manager private functions
|
||||||
|
|
||||||
|
|
||||||
|
/** allocate device node info structure;
|
||||||
|
* initially, ref_count is one to make sure node won't get destroyed by mistake
|
||||||
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
|
dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
|
||||||
device_node_info **new_node)
|
device_node_info **_node)
|
||||||
{
|
{
|
||||||
device_node_info *node;
|
device_node_info *node;
|
||||||
status_t res;
|
status_t res;
|
||||||
|
|
||||||
TRACE(("pnp_alloc_node()\n"));
|
|
||||||
|
|
||||||
node = calloc(1, sizeof(*node));
|
node = calloc(1, sizeof(*node));
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@@ -269,11 +244,16 @@ pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
|
|||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto err4;
|
goto err4;
|
||||||
|
|
||||||
|
list_init(&node->children);
|
||||||
|
|
||||||
node->parent = NULL;
|
node->parent = NULL;
|
||||||
node->rescan_depth = 0;
|
node->rescan_depth = 0;
|
||||||
|
node->registered = false;
|
||||||
|
#if 0
|
||||||
node->verifying = false;
|
node->verifying = false;
|
||||||
node->redetected = false;
|
node->redetected = false;
|
||||||
node->init_finished = false;
|
node->init_finished = false;
|
||||||
|
#endif
|
||||||
node->ref_count = 1;
|
node->ref_count = 1;
|
||||||
node->load_count = 0;
|
node->load_count = 0;
|
||||||
node->blocked_by_rescan = false;
|
node->blocked_by_rescan = false;
|
||||||
@@ -283,17 +263,10 @@ pnp_alloc_node(const device_attr *attrs, const io_resource_handle *resources,
|
|||||||
node->num_blocked_loads = 0;
|
node->num_blocked_loads = 0;
|
||||||
node->load_block_count = 0;
|
node->load_block_count = 0;
|
||||||
node->loading = 0;
|
node->loading = 0;
|
||||||
node->defer_probing = 0;
|
|
||||||
node->unprobed_children = NULL;
|
|
||||||
|
|
||||||
// make public (well, almost: it's not officially registered yet)
|
TRACE(("dm_allocate_node(): new node %p\n", node));
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
ADD_DL_LIST_HEAD(node, gNodeList, );
|
*_node = node;
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
*new_node = node;
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
@@ -309,45 +282,91 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// create links to parent node
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pnp_create_node_links(device_node_info *node, device_node_info *parent)
|
dm_add_child_node(device_node_info *parent, device_node_info *node)
|
||||||
{
|
{
|
||||||
TRACE(("pnp_create_node_links(%p, parent=%p)\n", node, parent));
|
TRACE(("dm_add_child_node(parent = %p, child = %p)\n", parent, node));
|
||||||
|
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
TRACE(("Adding parent link"));
|
// parent must not be destroyed as long as it has children
|
||||||
|
|
||||||
// parent must not be destroyed
|
|
||||||
parent->ref_count++;
|
parent->ref_count++;
|
||||||
node->parent = parent;
|
node->parent = parent;
|
||||||
|
|
||||||
// tell parent about us, so we get unregistered automatically if parent
|
// tell parent about us, so we get unregistered automatically if parent
|
||||||
// gets unregistered
|
// gets unregistered
|
||||||
ADD_DL_LIST_HEAD(node, parent->children, siblings_ );
|
list_add_item(&parent->children, node);
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public: get parent of node
|
void
|
||||||
|
dm_get_node_nolock(device_node_info *node)
|
||||||
device_node_handle
|
|
||||||
pnp_get_parent(device_node_handle node)
|
|
||||||
{
|
{
|
||||||
return node->parent;
|
node->ref_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// increase ref_count of node
|
||||||
|
|
||||||
|
void
|
||||||
|
dm_get_node(device_node_info *node)
|
||||||
|
{
|
||||||
|
TRACE(("dm_get_device_node(%p)\n", node));
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
node->ref_count++;
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// remove node reference and clean it up if necessary
|
||||||
|
// (node_lock must be hold)
|
||||||
|
|
||||||
|
void
|
||||||
|
dm_put_node_nolock(device_node_info *node)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
device_node_info *parent;
|
||||||
|
|
||||||
|
TRACE(("pnp_remove_node_ref_internal(ref_count of %p: %ld)\n", node, node->ref_count - 1));
|
||||||
|
|
||||||
|
// unregistered devices lose their I/O resources as soon as they
|
||||||
|
// are unloaded
|
||||||
|
if (!node->registered && node->loading == 0 && node->load_count == 0)
|
||||||
|
dm_release_node_resources(node);
|
||||||
|
|
||||||
|
if (--node->ref_count > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TRACE(("cleaning up %p (parent: %p)\n", node, node->parent));
|
||||||
|
|
||||||
|
// time to clean up
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
if (parent != NULL)
|
||||||
|
list_remove_item(&parent->children, node);
|
||||||
|
|
||||||
|
free_node(node);
|
||||||
|
|
||||||
|
// unrolled recursive call: decrease ref_count of parent as well
|
||||||
|
node = parent;
|
||||||
|
} while (node != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
// public: find node with some node attributes given
|
// public: find node with some node attributes given
|
||||||
|
|
||||||
device_node_info *
|
device_node_info *
|
||||||
pnp_find_device(device_node_info *parent, const device_attr *attrs)
|
dm_find_device(device_node_info *parent, const device_attr *attrs)
|
||||||
{
|
{
|
||||||
device_node_info *node, *found_node;
|
device_node_info *node, *found_node;
|
||||||
|
|
||||||
@@ -366,58 +385,8 @@ pnp_find_device(device_node_info *parent, const device_attr *attrs)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (attr = attrs; attr && attr->name; ++attr) {
|
for (attr = attrs; attr && attr->name; ++attr) {
|
||||||
bool equal = true;
|
device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
|
||||||
|
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
|
||||||
switch (attr->type) {
|
|
||||||
case B_UINT8_TYPE: {
|
|
||||||
uint8 value;
|
|
||||||
|
|
||||||
equal = pnp_get_attr_uint8_nolock( node, attr->name, &value, false ) == B_OK
|
|
||||||
&& value == attr->value.ui8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case B_UINT16_TYPE: {
|
|
||||||
uint16 value;
|
|
||||||
|
|
||||||
equal = pnp_get_attr_uint16_nolock( node, attr->name, &value, false ) == B_OK
|
|
||||||
&& value == attr->value.ui16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case B_UINT32_TYPE: {
|
|
||||||
uint32 value;
|
|
||||||
|
|
||||||
equal = pnp_get_attr_uint32_nolock( node, attr->name, &value, false ) == B_OK
|
|
||||||
&& value == attr->value.ui32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case B_UINT64_TYPE: {
|
|
||||||
uint64 value;
|
|
||||||
|
|
||||||
equal = pnp_get_attr_uint64_nolock( node, attr->name, &value, false ) == B_OK
|
|
||||||
&& value == attr->value.ui64;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case B_STRING_TYPE: {
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
equal = pnp_get_attr_string_nolock( node, attr->name, &str, false ) == B_OK
|
|
||||||
&& strcmp( str, attr->value.string ) == 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case B_RAW_TYPE: {
|
|
||||||
const void *data;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
equal = pnp_get_attr_raw_nolock( node, attr->name, &data, &len, false ) == B_OK
|
|
||||||
&& len == attr->value.raw.len
|
|
||||||
&& !memcmp(data, attr->value.raw.data, len);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!equal)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,52 +408,14 @@ err:
|
|||||||
|
|
||||||
return found_node;
|
return found_node;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
|
||||||
put_level(int32 level)
|
|
||||||
{
|
|
||||||
while (level-- > 0)
|
|
||||||
dprintf(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
dump_attribute(device_attr_info *attr, int32 level)
|
|
||||||
{
|
|
||||||
if (attr == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
put_level(level + 2);
|
|
||||||
dprintf("\"%s\" : ", attr->attr.name);
|
|
||||||
switch (attr->attr.type) {
|
|
||||||
case B_STRING_TYPE:
|
|
||||||
dprintf("string : \"%s\"", attr->attr.value.string);
|
|
||||||
break;
|
|
||||||
case B_UINT8_TYPE:
|
|
||||||
dprintf("uint8 : %u (%#x)", attr->attr.value.ui8, attr->attr.value.ui8);
|
|
||||||
break;
|
|
||||||
case B_UINT16_TYPE:
|
|
||||||
dprintf("uint16 : %u (%#x)", attr->attr.value.ui16, attr->attr.value.ui16);
|
|
||||||
break;
|
|
||||||
case B_UINT32_TYPE:
|
|
||||||
dprintf("uint32 : %lu (%#lx)", attr->attr.value.ui32, attr->attr.value.ui32);
|
|
||||||
break;
|
|
||||||
case B_UINT64_TYPE:
|
|
||||||
dprintf("uint64 : %Lu (%#Lx)", attr->attr.value.ui64, attr->attr.value.ui64);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dprintf("raw data");
|
|
||||||
}
|
|
||||||
dprintf("\n");
|
|
||||||
|
|
||||||
dump_attribute(attr->next, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dump_device_node_info(device_node_info *node, int32 level)
|
dm_dump_node(device_node_info *node, int32 level)
|
||||||
{
|
{
|
||||||
|
device_node_info *child = NULL;
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -492,14 +423,78 @@ dump_device_node_info(device_node_info *node, int32 level)
|
|||||||
dprintf("(%ld) @%p \"%s\"\n", level, node, node->driver ? node->driver->info.name : "---");
|
dprintf("(%ld) @%p \"%s\"\n", level, node, node->driver ? node->driver->info.name : "---");
|
||||||
dump_attribute(node->attributes, level);
|
dump_attribute(node->attributes, level);
|
||||||
|
|
||||||
dump_device_node_info(node->children, level + 1);
|
while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
|
||||||
dump_device_node_info(node->siblings_next, level);
|
dm_dump_node(child, level + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
nodes_init(void)
|
dm_init_nodes(void)
|
||||||
{
|
{
|
||||||
return benaphore_init(&gNodeLock, "device nodes");
|
return benaphore_init(&gNodeLock, "device nodes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
// Functions part of the module API
|
||||||
|
|
||||||
|
|
||||||
|
/** remove node reference and clean it up if necessary */
|
||||||
|
|
||||||
|
void
|
||||||
|
dm_put_node(device_node_info *node)
|
||||||
|
{
|
||||||
|
TRACE(("dm_put_node(%p)\n", node));
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
dm_put_node_nolock(node);
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_node_info *
|
||||||
|
dm_get_parent(device_node_info *node)
|
||||||
|
{
|
||||||
|
dm_get_node(node->parent);
|
||||||
|
return node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
dm_get_next_child_node(device_node_info *parent, device_node_info **_node,
|
||||||
|
const device_attr *attrs)
|
||||||
|
{
|
||||||
|
device_node_info *node = *_node;
|
||||||
|
if (node != NULL)
|
||||||
|
dm_put_node(node);
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
|
while ((node = (device_node_info *)list_get_next_item(&parent->children, node)) != NULL) {
|
||||||
|
const device_attr *attr;
|
||||||
|
|
||||||
|
// list contains removed devices too, so skip them
|
||||||
|
if (!node->registered)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (attr = attrs; attr && attr->name; ++attr) {
|
||||||
|
device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
|
||||||
|
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr != NULL && attr->name != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// we found a node
|
||||||
|
dm_get_node_nolock(node);
|
||||||
|
*_node = node;
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,41 +28,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/** notify a consumer that a device he might handle is added
|
|
||||||
* consumer_name - module name (!) of consumer
|
|
||||||
*/
|
|
||||||
|
|
||||||
status_t
|
|
||||||
pnp_notify_probe_by_module(device_node_info *node, const char *consumerName)
|
|
||||||
{
|
|
||||||
driver_module_info *consumer;
|
|
||||||
status_t status;
|
|
||||||
|
|
||||||
TRACE(("pnp_notify_probe_by_module(node %p, consumer: %s)\n", node, consumerName));
|
|
||||||
|
|
||||||
status = get_module(consumerName, (module_info **)&consumer);
|
|
||||||
if (status < B_OK) {
|
|
||||||
dprintf("Cannot load driver module %s (%s)\n", consumerName, strerror(status));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (consumer->register_device == NULL) {
|
|
||||||
dprintf("Driver %s has no register_device() hook\n", consumerName);
|
|
||||||
status = B_ERROR;
|
|
||||||
} else {
|
|
||||||
status = consumer->register_device(node);
|
|
||||||
TRACE(("Driver %s register_device() returned: %s\n", consumerName, strerror(status)));
|
|
||||||
}
|
|
||||||
|
|
||||||
put_module(consumerName);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** notify driver that it's device got removed */
|
/** notify driver that it's device got removed */
|
||||||
|
|
||||||
static status_t
|
status_t
|
||||||
notify_device_removed(device_node_info *node)
|
dm_notify_unregistration(device_node_info *node)
|
||||||
{
|
{
|
||||||
driver_module_info *driver;
|
driver_module_info *driver;
|
||||||
bool loaded;
|
bool loaded;
|
||||||
@@ -70,19 +39,21 @@ notify_device_removed(device_node_info *node)
|
|||||||
void *cookie;
|
void *cookie;
|
||||||
status_t res;
|
status_t res;
|
||||||
|
|
||||||
res = pnp_get_attr_string(node, PNP_DRIVER_DRIVER, &module_name, false);
|
res = pnp_get_attr_string(node, B_DRIVER_MODULE, &module_name, false);
|
||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
TRACE(("notify_device_removed(node: %p, consumer: %s)\n", node, module_name));
|
TRACE(("notify_device_removed(node: %p, consumer: %s)\n", node, module_name));
|
||||||
|
|
||||||
// block concurrent load/unload calls
|
// block concurrent load/unload calls
|
||||||
pnp_start_hook_call(node);
|
pnp_start_hook_call(node);
|
||||||
|
|
||||||
|
#if 0
|
||||||
// don't notify driver if it doesn't know that the device was
|
// don't notify driver if it doesn't know that the device was
|
||||||
// published
|
// published
|
||||||
if (!node->init_finished)
|
if (!node->init_finished)
|
||||||
goto skip;
|
goto skip;
|
||||||
|
#endif
|
||||||
|
|
||||||
// don't take node->loading into account - we want to know
|
// don't take node->loading into account - we want to know
|
||||||
// whether driver is loaded, not whether it is about to get loaded
|
// whether driver is loaded, not whether it is about to get loaded
|
||||||
@@ -132,20 +103,6 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** notify all drivers in <notify_list> that their node got removed */
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_notify_unregistration(device_node_info *notify_list)
|
|
||||||
{
|
|
||||||
device_node_info *node;
|
|
||||||
|
|
||||||
TRACE(("pnp_notify_unregistration()\n"));
|
|
||||||
|
|
||||||
for (node = notify_list; node; node = node->notify_next)
|
|
||||||
notify_device_removed(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** start driver hook call; must be called before a
|
/** start driver hook call; must be called before a
|
||||||
* load/unload/notification hook is called
|
* load/unload/notification hook is called
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -44,8 +44,16 @@ struct path_entry {
|
|||||||
char *path;
|
char *path;
|
||||||
dev_t device;
|
dev_t device;
|
||||||
ino_t node;
|
ino_t node;
|
||||||
|
int32 busses;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct module_entry {
|
||||||
|
struct list_link link;
|
||||||
|
char *name;
|
||||||
|
driver_module_info *driver;
|
||||||
|
float support;
|
||||||
|
bool no_connection;
|
||||||
|
};
|
||||||
|
|
||||||
// list of driver registration directories
|
// list of driver registration directories
|
||||||
const char *pnp_registration_dirs[2] = {
|
const char *pnp_registration_dirs[2] = {
|
||||||
@@ -62,6 +70,8 @@ static const char *kModulePaths[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern dev_t gBootDevice;
|
||||||
|
// from fs/vfs.cpp
|
||||||
|
|
||||||
class DirectoryIterator {
|
class DirectoryIterator {
|
||||||
public:
|
public:
|
||||||
@@ -207,6 +217,136 @@ DirectoryIterator::AddPath(const char *basePath, const char *subPath)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
struct path_entry *
|
||||||
|
new_path_entry(const char *path, dev_t device, ino_t node)
|
||||||
|
{
|
||||||
|
path_entry *entry = (path_entry *)malloc(sizeof(path_entry));
|
||||||
|
if (entry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
entry->path = strdup(path);
|
||||||
|
if (entry->path == NULL) {
|
||||||
|
free(entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->device = device;
|
||||||
|
entry->node = node;
|
||||||
|
entry->busses = 0;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct path_entry *
|
||||||
|
copy_path_entry(path_entry *entry)
|
||||||
|
{
|
||||||
|
path_entry *newEntry = (path_entry *)malloc(sizeof(struct path_entry));
|
||||||
|
if (newEntry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*newEntry = *entry;
|
||||||
|
newEntry->path = strdup(entry->path);
|
||||||
|
if (newEntry->path == NULL) {
|
||||||
|
free(newEntry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
free_module_entry(module_entry *entry)
|
||||||
|
{
|
||||||
|
if (entry->name != NULL && entry->driver != NULL)
|
||||||
|
put_module(entry->name);
|
||||||
|
|
||||||
|
free(entry->name);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct module_entry *
|
||||||
|
new_module_entry(const char *name, driver_module_info *driver)
|
||||||
|
{
|
||||||
|
module_entry *entry = (module_entry *)malloc(sizeof(module_entry));
|
||||||
|
if (entry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
entry->name = strdup(name);
|
||||||
|
if (entry->name == NULL) {
|
||||||
|
free(entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->driver = driver;
|
||||||
|
entry->support = -1.0f;
|
||||||
|
entry->no_connection = false;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static module_entry *
|
||||||
|
find_module_entry(struct list *list, const char *name)
|
||||||
|
{
|
||||||
|
module_entry *entry = NULL;
|
||||||
|
|
||||||
|
while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) {
|
||||||
|
if (!strcmp(entry->name, name))
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
add_device_node(struct list *list, device_node_info *node)
|
||||||
|
{
|
||||||
|
node_entry *entry = (node_entry *)malloc(sizeof(node_entry));
|
||||||
|
if (entry == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
entry->node = node;
|
||||||
|
|
||||||
|
uint8 exploreLast = false;
|
||||||
|
pnp_get_attr_uint8(node, B_DRIVER_EXPLORE_LAST, &exploreLast, false);
|
||||||
|
|
||||||
|
if (exploreLast)
|
||||||
|
list_add_link_to_tail(list, &entry->link);
|
||||||
|
else
|
||||||
|
list_add_link_to_head(list, &entry->link);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
get_next_device_node(struct list *list, uint32 *_cookie, device_node_info **_node)
|
||||||
|
{
|
||||||
|
node_entry *entry = (node_entry *)list_get_next_item(list, (void *)*_cookie);
|
||||||
|
if (entry == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
*_node = entry->node;
|
||||||
|
*_cookie = (uint32)entry;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_device_nodes(struct list *list)
|
||||||
|
{
|
||||||
|
struct node_entry *entry;
|
||||||
|
|
||||||
|
while ((entry = (node_entry *)list_remove_head_item(list)) != NULL) {
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
/** notify a consumer that a device he might handle is added
|
/** notify a consumer that a device he might handle is added
|
||||||
* fileName - file name of consumer
|
* fileName - file name of consumer
|
||||||
* (moved to end of file to avoid inlining)
|
* (moved to end of file to avoid inlining)
|
||||||
@@ -271,7 +411,7 @@ notify_probe_by_file(device_node_info *node, const char *fileName)
|
|||||||
strlcat(module_name, "/", B_PATH_NAME_LENGTH);
|
strlcat(module_name, "/", B_PATH_NAME_LENGTH);
|
||||||
strlcat(module_name, type, B_PATH_NAME_LENGTH);
|
strlcat(module_name, type, B_PATH_NAME_LENGTH);
|
||||||
|
|
||||||
res = pnp_notify_probe_by_module(node, module_name);
|
res = dm_register_child_device(node, module_name);
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
free(resolved_path);
|
free(resolved_path);
|
||||||
@@ -391,14 +531,14 @@ try_drivers(device_node_info *node, char *directory,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** find normal consumer of node that are stored under <dir>; first, we
|
/** find normal child of node that are stored under <dir>; first, we
|
||||||
* look for a specific driver; if none could be found, find a generic
|
* look for a specific driver; if none could be found, find a generic
|
||||||
* one path, buffer - used as scratch buffer (all of size B_PATH_NAME_LENGTH + 1)
|
* one path, buffer - used as scratch buffer (all of size B_PATH_NAME_LENGTH + 1)
|
||||||
* return: B_NAME_NOT_FOUND if no consumer could be found
|
* return: B_NAME_NOT_FOUND if no consumer could be found
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
find_normal_consumer(device_node_info *node, const char *dir,
|
find_normal_child(device_node_info *node, const char *dir,
|
||||||
const char *filename_pattern, int num_parts,
|
const char *filename_pattern, int num_parts,
|
||||||
char *path, char *buffer, bool *found_normal_driver)
|
char *path, char *buffer, bool *found_normal_driver)
|
||||||
{
|
{
|
||||||
@@ -465,7 +605,7 @@ find_normal_consumer(device_node_info *node, const char *dir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** pre-process dynamic consumer name pattern.
|
/** pre-process dynamic child name pattern.
|
||||||
* split into directory and pattern and count split positions;
|
* split into directory and pattern and count split positions;
|
||||||
* further, remove quotes from directory
|
* further, remove quotes from directory
|
||||||
* pattern - pattern of consumer name
|
* pattern - pattern of consumer name
|
||||||
@@ -476,7 +616,7 @@ find_normal_consumer(device_node_info *node, const char *dir,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
preprocess_consumer_names(const char *pattern, char *buffer,
|
preprocess_child_names(const char *pattern, char *buffer,
|
||||||
char **filename_pattern, int *const num_parts)
|
char **filename_pattern, int *const num_parts)
|
||||||
{
|
{
|
||||||
char *str, *dest;
|
char *str, *dest;
|
||||||
@@ -547,7 +687,7 @@ preprocess_consumer_names(const char *pattern, char *buffer,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
notify_dynamic_consumer(device_node_info *node, const char *bus,
|
register_dynamic_child_device(device_node_info *node, const char *bus,
|
||||||
const char *pattern, bool *has_normal_driver)
|
const char *pattern, bool *has_normal_driver)
|
||||||
{
|
{
|
||||||
status_t status;
|
status_t status;
|
||||||
@@ -555,7 +695,7 @@ notify_dynamic_consumer(device_node_info *node, const char *bus,
|
|||||||
char *filename_pattern;
|
char *filename_pattern;
|
||||||
int num_parts;
|
int num_parts;
|
||||||
|
|
||||||
TRACE(("notify_dynamic_consumer(bus = %s, pattern = %s, has_normal_driver = %d)\n",
|
TRACE(("register_dynamic_child_device(bus = %s, pattern = %s, has_normal_driver = %d)\n",
|
||||||
bus, pattern, *has_normal_driver));
|
bus, pattern, *has_normal_driver));
|
||||||
|
|
||||||
if (pattern == NULL)
|
if (pattern == NULL)
|
||||||
@@ -566,14 +706,14 @@ notify_dynamic_consumer(device_node_info *node, const char *bus,
|
|||||||
if (buffers == NULL)
|
if (buffers == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
status = preprocess_consumer_names(pattern, buffers + 2 * (B_PATH_NAME_LENGTH + 1),
|
status = preprocess_child_names(pattern, buffers + 2 * (B_PATH_NAME_LENGTH + 1),
|
||||||
&filename_pattern, &num_parts);
|
&filename_pattern, &num_parts);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (!*has_normal_driver) {
|
if (!*has_normal_driver) {
|
||||||
// find specific/generic consumer
|
// find specific/generic consumer
|
||||||
status = find_normal_consumer(node, bus, filename_pattern, num_parts,
|
status = find_normal_child(node, bus, filename_pattern, num_parts,
|
||||||
buffers, buffers + B_PATH_NAME_LENGTH + 1, has_normal_driver);
|
buffers, buffers + B_PATH_NAME_LENGTH + 1, has_normal_driver);
|
||||||
if (status != B_OK && status != B_NAME_NOT_FOUND)
|
if (status != B_OK && status != B_NAME_NOT_FOUND)
|
||||||
// only abort if there was a "real" problem;
|
// only abort if there was a "real" problem;
|
||||||
@@ -600,6 +740,7 @@ err:
|
|||||||
free(buffers);
|
free(buffers);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static path_entry *
|
static path_entry *
|
||||||
@@ -639,19 +780,22 @@ load_driver(const char *path)
|
|||||||
name++;
|
name++;
|
||||||
|
|
||||||
// For a valid device driver the following exports are required
|
// For a valid device driver the following exports are required
|
||||||
|
|
||||||
|
uint32 *api_version;
|
||||||
|
if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, (void **)&api_version) != B_OK)
|
||||||
|
dprintf("%s: api_version missing\n", name);
|
||||||
|
|
||||||
device_hooks *(*find_device)(const char *);
|
device_hooks *(*find_device)(const char *);
|
||||||
const char **(*publish_devices)(void);
|
const char **(*publish_devices)(void);
|
||||||
uint32 *api_version;
|
|
||||||
if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, (void **)&publish_devices) != B_OK
|
if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, (void **)&publish_devices) != B_OK
|
||||||
|| get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, (void **)&api_version) != B_OK
|
|
||||||
|| get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, (void **)&find_device) != B_OK) {
|
|| get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, (void **)&find_device) != B_OK) {
|
||||||
dprintf("%s: mandatory driver symbol(s) missing!\n", name);
|
dprintf("%s: mandatory driver symbol(s) missing!\n", name);
|
||||||
status = B_BAD_VALUE;
|
status = B_BAD_VALUE;
|
||||||
goto error1;
|
goto error1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test for init_hardware() and call it
|
// Init the driver
|
||||||
|
|
||||||
if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT,
|
if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT,
|
||||||
(void **)&init_hardware) == B_OK
|
(void **)&init_hardware) == B_OK
|
||||||
&& (status = init_hardware()) != B_OK) {
|
&& (status = init_hardware()) != B_OK) {
|
||||||
@@ -660,19 +804,6 @@ load_driver(const char *path)
|
|||||||
goto error1;
|
goto error1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, so we now have what appears to be a valid module that has
|
|
||||||
* completed init_hardware and thus thinks it should be used.
|
|
||||||
* ToDo:
|
|
||||||
* - this is bogus!
|
|
||||||
* - the driver init routines should be called by devfs and
|
|
||||||
* only when the driver is first needed. However, that level
|
|
||||||
* level of support is not yet in devfs, so we have a hack
|
|
||||||
* here that calls the init_driver function at this point.
|
|
||||||
* As a result we will check to see if we actually manage to
|
|
||||||
* publish the device, and if we do we will keep the module
|
|
||||||
* loaded.
|
|
||||||
* - remove this when devfs is fixed!
|
|
||||||
*/
|
|
||||||
if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT,
|
if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT,
|
||||||
(void **)&init_driver) == B_OK
|
(void **)&init_driver) == B_OK
|
||||||
&& (status = init_driver()) != B_OK) {
|
&& (status = init_driver()) != B_OK) {
|
||||||
@@ -681,7 +812,13 @@ load_driver(const char *path)
|
|||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The driver has successfully been initialized, now we can
|
||||||
|
// finally publish its device entries
|
||||||
|
|
||||||
// we keep the driver loaded if it exports at least a single interface
|
// we keep the driver loaded if it exports at least a single interface
|
||||||
|
// ToDo: we could/should always unload drivers until they will be used for real
|
||||||
|
// ToDo: this function is probably better kept in devfs, so that it could remember
|
||||||
|
// the driver stuff (and even keep it loaded if there is enough memory)
|
||||||
devicePaths = publish_devices();
|
devicePaths = publish_devices();
|
||||||
if (devicePaths == NULL) {
|
if (devicePaths == NULL) {
|
||||||
dprintf("%s: publish_devices() returned NULL.\n", name);
|
dprintf("%s: publish_devices() returned NULL.\n", name);
|
||||||
@@ -702,7 +839,6 @@ load_driver(const char *path)
|
|||||||
|
|
||||||
status = B_ERROR; // whatever...
|
status = B_ERROR; // whatever...
|
||||||
|
|
||||||
|
|
||||||
error3:
|
error3:
|
||||||
{
|
{
|
||||||
status_t (*uninit_driver)(void);
|
status_t (*uninit_driver)(void);
|
||||||
@@ -712,12 +848,12 @@ error3:
|
|||||||
}
|
}
|
||||||
|
|
||||||
error2:
|
error2:
|
||||||
{
|
{
|
||||||
status_t (*uninit_hardware)(void);
|
status_t (*uninit_hardware)(void);
|
||||||
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
|
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
|
||||||
(void **)&uninit_hardware) == B_OK)
|
(void **)&uninit_hardware) == B_OK)
|
||||||
uninit_hardware();
|
uninit_hardware();
|
||||||
}
|
}
|
||||||
error1:
|
error1:
|
||||||
/* If we've gotten here then the driver will be unloaded and an
|
/* If we've gotten here then the driver will be unloaded and an
|
||||||
* error code returned.
|
* error code returned.
|
||||||
@@ -740,11 +876,25 @@ load_driver_symbols(const char *driverName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Iterates over the given list and tries to load all drivers and modules
|
||||||
|
* in that list.
|
||||||
|
* The list is emptied and freed during the traversal.
|
||||||
|
*
|
||||||
|
* ToDo: Old style drivers will be initialized as well, new style driver
|
||||||
|
* handling is not yet done.
|
||||||
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
try_drivers(struct list &list)
|
try_drivers(struct list &list, bool tryBusDrivers)
|
||||||
{
|
{
|
||||||
path_entry *entry;
|
path_entry *entry;
|
||||||
while ((entry = (path_entry *)list_remove_head_item(&list)) != NULL) {
|
while ((entry = (path_entry *)list_remove_head_item(&list)) != NULL) {
|
||||||
|
if (!tryBusDrivers && entry->busses) {
|
||||||
|
free(entry->path);
|
||||||
|
free(entry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
image_id image = load_kernel_add_on(entry->path);
|
image_id image = load_kernel_add_on(entry->path);
|
||||||
if (image >= 0) {
|
if (image >= 0) {
|
||||||
// check if it's a driver module
|
// check if it's a driver module
|
||||||
@@ -771,127 +921,393 @@ try_drivers(struct list &list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static module_entry *
|
||||||
|
remove_best_entry(struct list *list)
|
||||||
|
{
|
||||||
|
module_entry *bestEntry = NULL;
|
||||||
|
module_entry *entry = NULL;
|
||||||
|
|
||||||
|
while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) {
|
||||||
|
if (entry->no_connection || entry->driver == NULL
|
||||||
|
|| entry->driver->register_device == NULL
|
||||||
|
|| entry->support <= 0.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bestEntry == NULL || bestEntry->support < entry->support)
|
||||||
|
bestEntry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestEntry) {
|
||||||
|
list_remove_item(list, bestEntry);
|
||||||
|
return bestEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
register_supporting_child_devices(device_node_info *node, struct list *list)
|
||||||
|
{
|
||||||
|
// See if this node has a connection to offer
|
||||||
|
char *hasConnection = NULL;
|
||||||
|
// this is a bit ugly as we don't access the string
|
||||||
|
// but just test it against NULL
|
||||||
|
if (pnp_get_attr_string(node, PNP_DRIVER_CONNECTION, &hasConnection, false) == B_OK)
|
||||||
|
free(hasConnection);
|
||||||
|
dprintf("has connection? %s\n", hasConnection ? "yes" : "no");
|
||||||
|
|
||||||
|
// first ask each module for level of support
|
||||||
|
|
||||||
|
module_entry *bestEntry = NULL;
|
||||||
|
module_entry *entry = NULL;
|
||||||
|
while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) {
|
||||||
|
if (entry->driver == NULL) {
|
||||||
|
if (get_module(entry->name, (module_info **)&entry->driver) != B_OK)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->support = entry->driver->supports_device(node, &entry->no_connection);
|
||||||
|
dprintf("module: %s, support: %d\n", entry->name, (int)(entry->support * 1000));
|
||||||
|
|
||||||
|
if (!hasConnection)
|
||||||
|
entry->no_connection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// register best module with a connection
|
||||||
|
|
||||||
|
while ((entry = remove_best_entry(list)) != NULL) {
|
||||||
|
status_t status = entry->driver->register_device(node);
|
||||||
|
dprintf("tried best module: %s: %s\n", entry->name, strerror(status));
|
||||||
|
free_module_entry(entry);
|
||||||
|
|
||||||
|
if (status == B_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// register all modules that don't need a connection
|
||||||
|
// and empty the list
|
||||||
|
|
||||||
|
while ((entry = (module_entry *)list_remove_head_item(list)) != NULL) {
|
||||||
|
if (entry->no_connection && entry->driver != NULL
|
||||||
|
&& entry->driver->register_device != NULL
|
||||||
|
&& entry->support > 0.0) {
|
||||||
|
dprintf("register rest: %s\n", entry->name);
|
||||||
|
entry->driver->register_device(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("free %s\n", entry->name);
|
||||||
|
free_module_entry(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_driver_module(const char *name, int32 length)
|
||||||
|
{
|
||||||
|
if (length == -1)
|
||||||
|
length = strlen(name);
|
||||||
|
|
||||||
|
return !strcmp(name + length - 9, "device_v1");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
get_loaded_modules(struct list *modules, const char *bus, const char *device)
|
||||||
|
{
|
||||||
|
TRACE(("get_loaded_modules(bus = %s, device = %s)\n", bus, device));
|
||||||
|
|
||||||
|
bool listWasEmpty = list_is_empty(modules);
|
||||||
|
|
||||||
|
char name[B_FILE_NAME_LENGTH];
|
||||||
|
size_t size = sizeof(name);
|
||||||
|
uint32 cookie = 0;
|
||||||
|
while (get_next_loaded_module_name(&cookie, name, &size) == B_OK) {
|
||||||
|
int32 length = size;
|
||||||
|
size = sizeof(name);
|
||||||
|
|
||||||
|
if (!is_driver_module(name, length))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TRACE((" \"%s\" is driver module!\n", name));
|
||||||
|
|
||||||
|
driver_module_info *info;
|
||||||
|
if (get_module(name, (module_info **)&info) == B_OK) {
|
||||||
|
if (info->get_supported_paths == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char **busses, **devices;
|
||||||
|
info->get_supported_paths(&busses, &devices);
|
||||||
|
|
||||||
|
bool support = bus == NULL;
|
||||||
|
|
||||||
|
// search for the bus
|
||||||
|
|
||||||
|
if (bus != NULL && busses != NULL) {
|
||||||
|
for (int32 i = 0; busses[i]; i++) {
|
||||||
|
if (!strcmp(bus, busses[i])) {
|
||||||
|
dprintf("\tfound %s!!\n", busses[i]);
|
||||||
|
support = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (support) {
|
||||||
|
// search for the device
|
||||||
|
|
||||||
|
support = device == NULL;
|
||||||
|
|
||||||
|
if (device != NULL && devices != NULL) {
|
||||||
|
for (int32 i = 0; devices[i]; i++) {
|
||||||
|
if (!strncmp(device, devices[i], strlen(device))) {
|
||||||
|
dprintf("\tfound %s!!\n", devices[i]);
|
||||||
|
support = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (support && !listWasEmpty) {
|
||||||
|
// make sure we don't add the same module twice
|
||||||
|
if (find_module_entry(modules, name) != NULL)
|
||||||
|
support = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (support) {
|
||||||
|
module_entry *entry = new_module_entry(name, info);
|
||||||
|
if (entry == NULL) {
|
||||||
|
put_module(name);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("\tadd module %s to list\n", name);
|
||||||
|
list_add_item(modules, entry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
put_module(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
get_nodes_for_device_type(device_node_info *node, struct list *list, const char *type)
|
||||||
|
{
|
||||||
|
bool matches = false;
|
||||||
|
|
||||||
|
// see if there is a B_DRIVER_DEVICE_TYPE that matches the query
|
||||||
|
|
||||||
|
char *deviceType = NULL;
|
||||||
|
if (pnp_get_attr_string(node, B_DRIVER_DEVICE_TYPE, &deviceType, false) == B_OK) {
|
||||||
|
if (!strncmp(deviceType, type, strlen(type)))
|
||||||
|
matches = true;
|
||||||
|
|
||||||
|
free(deviceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!matches) {
|
||||||
|
// we also accept any dump busses
|
||||||
|
uint8 onDemand = false;
|
||||||
|
pnp_get_attr_uint8(node, B_DRIVER_FIND_DEVICES_ON_DEMAND, &onDemand, false);
|
||||||
|
|
||||||
|
if (onDemand)
|
||||||
|
matches = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
dprintf("** NODE MATCHES TYPE %s\n", type);
|
||||||
|
dm_dump_node(node, 0);
|
||||||
|
return add_device_node(list, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// search child nodes, then
|
||||||
|
device_node_info *child = NULL;
|
||||||
|
while (dm_get_next_child_node(node, &child, NULL) == B_OK) {
|
||||||
|
status_t status = get_nodes_for_device_type(child, list, type);
|
||||||
|
if (status != B_OK) {
|
||||||
|
dm_put_node(child);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
// device manager private API
|
// device manager private API
|
||||||
|
|
||||||
|
|
||||||
|
/** Register the device of a child for the \a node that might accept it.
|
||||||
|
* childName - module name of child/consumer
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_t
|
||||||
|
dm_register_child_device(device_node_info *node, const char *childName)
|
||||||
|
{
|
||||||
|
driver_module_info *child;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
TRACE(("dm_register_child_device(node = %p, child = %s)\n", node, childName));
|
||||||
|
|
||||||
|
status = get_module(childName, (module_info **)&child);
|
||||||
|
if (status < B_OK) {
|
||||||
|
dprintf("Cannot load driver module %s (%s)\n", childName, strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child->register_device != NULL) {
|
||||||
|
status = child->register_device(node);
|
||||||
|
if (status != B_OK) {
|
||||||
|
TRACE(("dm_register_child_device(): Driver %s returned: %s\n",
|
||||||
|
childName, strerror(status)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dprintf("Driver %s has no register_device() hook\n", childName);
|
||||||
|
status = B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
put_module(childName);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** find and notify dynamic consumers that device was added
|
/** find and notify dynamic consumers that device was added
|
||||||
* errors returned by consumers aren't reported, only problems
|
* errors returned by consumers aren't reported, only problems
|
||||||
* like malformed consumer patterns
|
* like malformed consumer patterns
|
||||||
*/
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_notify_dynamic_consumers(device_node_info *node)
|
dm_register_dynamic_child_devices(device_node_info *node)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
char *buffer;
|
char *buffer;
|
||||||
char *bus;
|
char *bus;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
int32 i, found = 0;
|
int32 i, found = 0;
|
||||||
|
|
||||||
TRACE(("pnp_notify_dynamic_consumers(node = %p)\n", node));
|
TRACE(("dm_register_dynamic_child_devices(node = %p)\n", node));
|
||||||
|
|
||||||
if (pnp_get_attr_string(node, PNP_DRIVER_CONSUMER_BUS, &bus, false) != B_OK)
|
if (pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false) != B_OK)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
TRACE((" Search bus: \"%s\"\n", bus));
|
TRACE((" Search bus: \"%s\"\n", bus));
|
||||||
|
|
||||||
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
|
if (gBootDevice < 0) {
|
||||||
if (buffer == NULL) {
|
// there is no boot device yet, we have to scan the already
|
||||||
status = B_NO_MEMORY;
|
// loaded and built-in modules
|
||||||
goto err;
|
struct list modules;
|
||||||
}
|
list_init(&modules);
|
||||||
|
|
||||||
// first, append nothing, then "/0", "/1" etc.
|
status = get_loaded_modules(&modules, bus, NULL);
|
||||||
for (i = -1; ; ++i) {
|
if (status != B_OK)
|
||||||
bool noSpecificDriver = false;
|
return status;
|
||||||
char *consumer;
|
|
||||||
|
|
||||||
strcpy(buffer, PNP_DRIVER_CONSUMER_MAPPING);
|
register_supporting_child_devices(node, &modules);
|
||||||
if (i >= 0)
|
return B_OK;
|
||||||
sprintf(buffer + strlen( buffer ), "/%ld", i);
|
} else {
|
||||||
|
// ToDo: this is completely outdated and must be redone!
|
||||||
|
status = B_ERROR;
|
||||||
|
#if 0
|
||||||
|
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
// if no more dynamic consumers, cancel loop silently
|
// first, append nothing, then "/0", "/1" etc.
|
||||||
if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) {
|
for (i = -1; ; ++i) {
|
||||||
// starting with .../0 is OK, so ignore error if i = -1
|
bool noSpecificDriver = false;
|
||||||
if (i == -1)
|
char *consumer;
|
||||||
continue;
|
|
||||||
else
|
strcpy(buffer, B_DRIVER_MAPPING);
|
||||||
|
if (i >= 0)
|
||||||
|
sprintf(buffer + strlen( buffer ), "/%ld", i);
|
||||||
|
|
||||||
|
// if no more dynamic consumers, cancel loop silently
|
||||||
|
if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) {
|
||||||
|
// starting with .../0 is OK, so ignore error if i = -1
|
||||||
|
if (i == -1)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE((" Consumer pattern %ld: %s\n", i, consumer));
|
||||||
|
status = register_dynamic_child_device(node, bus, consumer, &noSpecificDriver);
|
||||||
|
|
||||||
|
free(consumer);
|
||||||
|
found++;
|
||||||
|
|
||||||
|
if (status != B_OK) {
|
||||||
|
// this is only reached if a serious error occured,
|
||||||
|
// see register_dynamic_child_device()
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
TRACE((" Consumer pattern %ld: %s\n", i, consumer));
|
|
||||||
status = notify_dynamic_consumer(node, bus, consumer, &noSpecificDriver);
|
|
||||||
|
|
||||||
free(consumer);
|
|
||||||
found++;
|
|
||||||
|
|
||||||
if (status != B_OK) {
|
|
||||||
// this is only reached if a serious error occured,
|
|
||||||
// see notify_dynamic_consumer()
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
if (found == 0) {
|
if (found == 0) {
|
||||||
// no requirement for a special mapping, so we're just scanning the bus directory
|
// no requirement for a special mapping, so we're just scanning the bus directory
|
||||||
bool noSpecificDriver = false;
|
bool noSpecificDriver = false;
|
||||||
status = notify_dynamic_consumer(node, bus, NULL, &noSpecificDriver);
|
status = register_dynamic_child_device(node, bus, NULL, &noSpecificDriver);
|
||||||
}
|
}
|
||||||
|
|
||||||
// supposed to go through
|
// supposed to go through
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
#endif
|
||||||
err:
|
err:
|
||||||
free(bus);
|
free(bus);
|
||||||
return status;
|
return status;
|
||||||
#else
|
|
||||||
return B_OK;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Notify fixed consumers that device was added; in contrast to dynamic
|
/** Register all fixed child devices of of the given \a node; in contrast
|
||||||
* consumers, errors reported by fixed consumers are not ignored but
|
* to dynamic child devices, errors reported by fixed child devices are
|
||||||
* returned.
|
* not ignored but returned, and regarded critical.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_notify_fixed_consumers(device_node_info *node)
|
dm_register_fixed_child_devices(device_node_info *node)
|
||||||
{
|
{
|
||||||
int i;
|
TRACE(("dm_register_fixed_child_devices(node = %p)\n", node));
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
TRACE(("pnp_notify_fixed_consumers(node = %p)\n", node));
|
char *buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
|
||||||
|
|
||||||
buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1);
|
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
// first, append nothing, then "/0", "/1" etc.
|
// first, append nothing, then "/0", "/1" etc.
|
||||||
for (i = -1; ; ++i) {
|
for (int32 i = -1; ; ++i) {
|
||||||
char *consumer;
|
char *childName;
|
||||||
|
|
||||||
strcpy(buffer, PNP_DRIVER_FIXED_CONSUMER);
|
strcpy(buffer, B_DRIVER_FIXED_CHILD);
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
sprintf(buffer + strlen(buffer), "/%d", i);
|
sprintf(buffer + strlen(buffer), "/%ld", i);
|
||||||
|
|
||||||
// if no more fixed consumers, cancel loop silently
|
// if no more fixed consumers, cancel loop silently
|
||||||
if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK)
|
if (pnp_get_attr_string(node, buffer, &childName, false) != B_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
TRACE(("Consumer %d: %s\n", i, consumer));
|
TRACE(("Consumer %ld: %s\n", i, childName));
|
||||||
|
|
||||||
if (pnp_notify_probe_by_module(node, consumer) != B_OK) {
|
if (dm_register_child_device(node, childName) != B_OK) {
|
||||||
dprintf("Cannot notify fixed consumer %s\n", consumer);
|
dprintf("Cannot register fixed child device %s\n", childName);
|
||||||
|
|
||||||
// report error if fixed consumers couldn't be loaded
|
// report error if fixed consumers couldn't be loaded
|
||||||
// as they are obviously crucial (else they wouldn't be fixed)
|
// as they are obviously crucial (else they wouldn't be fixed)
|
||||||
free(consumer);
|
|
||||||
|
// ToDo: what about the devices we already registered up to this point?
|
||||||
|
free(childName);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return B_NAME_NOT_FOUND;
|
return B_NAME_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(consumer);
|
free(childName);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@@ -899,49 +1315,65 @@ pnp_notify_fixed_consumers(device_node_info *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
static status_t
|
||||||
probe_for_device_type(const char *type)
|
probe_for_driver_modules(const char *type)
|
||||||
{
|
{
|
||||||
|
TRACE(("probe_for_driver_modules(type = %s)\n", type));
|
||||||
|
|
||||||
// search a node with an open connection of the specified type
|
// search a node with an open connection of the specified type
|
||||||
// or notify bus managers to get one
|
// or notify bus managers to get one
|
||||||
|
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
|
|
||||||
// build list of potential drivers for that type
|
|
||||||
|
|
||||||
struct list drivers;
|
struct list drivers;
|
||||||
list_init(&drivers);
|
list_init(&drivers);
|
||||||
|
|
||||||
char devType[64];
|
if (gBootDevice < 0) {
|
||||||
snprintf(devType, sizeof(devType), "drivers/dev%s%s", type[0] ? "/" : "", type);
|
struct list nodes;
|
||||||
|
list_init(&nodes);
|
||||||
|
|
||||||
DirectoryIterator iterator(kModulePaths, devType, false);
|
get_nodes_for_device_type(gRootNode, &nodes, type);
|
||||||
|
|
||||||
|
device_node_info *node;
|
||||||
|
uint32 cookie = 0;
|
||||||
|
while (get_next_device_node(&nodes, &cookie, &node) == B_OK) {
|
||||||
|
char *bus;
|
||||||
|
if (pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false) == B_OK) {
|
||||||
|
struct list drivers;
|
||||||
|
list_init(&drivers);
|
||||||
|
get_loaded_modules(&drivers, bus, type);
|
||||||
|
|
||||||
|
register_supporting_child_devices(node, &drivers);
|
||||||
|
|
||||||
|
free(bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_device_nodes(&nodes);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build list of potential drivers for that type
|
||||||
|
|
||||||
|
DirectoryIterator iterator(kModulePaths, type, false);
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
KPath path;
|
KPath path;
|
||||||
|
|
||||||
while (iterator.GetNext(path, stat) == B_OK) {
|
while (iterator.GetNext(path, stat) == B_OK) {
|
||||||
path_entry *entry = (path_entry *)malloc(sizeof(path_entry));
|
|
||||||
if (entry == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
entry->path = strdup(path.Path());
|
|
||||||
if (entry->path == NULL) {
|
|
||||||
free(entry);
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR(stat.st_mode)) {
|
if (S_ISDIR(stat.st_mode)) {
|
||||||
// We need to make sure that drivers in ie. "audio/raw/" can
|
// We need to make sure that drivers in ie. "audio/raw/" can
|
||||||
// be found as well - therefore, we must make sure that "audio"
|
// be found as well - therefore, we must make sure that "audio"
|
||||||
// exists on /dev.
|
// exists on /dev.
|
||||||
if (type[0])
|
int32 length = strlen("drivers/dev/");
|
||||||
devfs_publish_directory(type);
|
if (!strncmp(type, "drivers/dev/", length))
|
||||||
|
devfs_publish_directory(type + length);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
entry->device = stat.st_dev;
|
|
||||||
entry->node = stat.st_ino;
|
|
||||||
|
|
||||||
dprintf("found potential driver: %s\n", path.Path());
|
path_entry *entry = new_path_entry(path.Path(), stat.st_dev, stat.st_ino);
|
||||||
|
if (entry == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
TRACE(("found potential driver: %s\n", path.Path()));
|
||||||
list_add_item(&drivers, entry);
|
list_add_item(&drivers, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -959,13 +1391,23 @@ probe_for_device_type(const char *type)
|
|||||||
struct list driversForBus;
|
struct list driversForBus;
|
||||||
list_init(&driversForBus);
|
list_init(&driversForBus);
|
||||||
|
|
||||||
|
dprintf("bus: %s\n", path.Leaf());
|
||||||
|
|
||||||
while (busIterator.GetNext(path, stat) == B_OK) {
|
while (busIterator.GetNext(path, stat) == B_OK) {
|
||||||
path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, stat.st_ino);
|
path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, stat.st_ino);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// we found the driver here, so we should check it
|
entry->busses++;
|
||||||
list_remove_link(&entry->link);
|
// mark this entry as being used by a bus
|
||||||
|
|
||||||
|
// ToDo: we don't need to remember drivers when there is no bus for them
|
||||||
|
// (ie. no need to store ISA drivers when there is no ISA bus in the system)
|
||||||
|
|
||||||
|
entry = copy_path_entry(entry);
|
||||||
|
if (entry == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
list_add_item(&driversForBus, entry);
|
list_add_item(&driversForBus, entry);
|
||||||
dprintf("found driver for bus \"%s\": \"%s\"\n", path.Path(), entry->path);
|
dprintf("found driver for bus \"%s\": \"%s\"\n", path.Path(), entry->path);
|
||||||
}
|
}
|
||||||
@@ -973,11 +1415,22 @@ probe_for_device_type(const char *type)
|
|||||||
// ToDo: do something with the bus drivers... :)
|
// ToDo: do something with the bus drivers... :)
|
||||||
// ToDo: ask bus manager for driver (via mapping)
|
// ToDo: ask bus manager for driver (via mapping)
|
||||||
// ToDo: find all nodes where this driver could be attached to
|
// ToDo: find all nodes where this driver could be attached to
|
||||||
try_drivers(driversForBus);
|
try_drivers(driversForBus, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDo: do something with the remaining drivers... :)
|
// ToDo: do something with the remaining drivers... :)
|
||||||
try_drivers(drivers);
|
try_drivers(drivers, false);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
probe_for_device_type(const char *type)
|
||||||
|
{
|
||||||
|
TRACE(("probe_for_device_type(type = %s)\n", type));
|
||||||
|
|
||||||
|
char deviceType[64];
|
||||||
|
snprintf(deviceType, sizeof(deviceType), "drivers/dev%s%s", type[0] ? "/" : "", type);
|
||||||
|
|
||||||
|
return probe_for_driver_modules(deviceType);
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,22 +29,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// decrease ref_count of unregistered nodes, specified by <node_list>
|
/** mark node being registered, so it can be accessed via load_driver() */
|
||||||
|
|
||||||
void
|
|
||||||
pnp_unref_unregistered_nodes(device_node_info *node_list)
|
|
||||||
{
|
|
||||||
device_node_info *node, *next_node;
|
|
||||||
|
|
||||||
for (node = node_list; node; node = next_node) {
|
|
||||||
next_node = node->notify_next;
|
|
||||||
|
|
||||||
pnp_remove_node_ref(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// mark node being registered, so it can be accessed via load_driver()
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
mark_node_registered(device_node_info *node)
|
mark_node_registered(device_node_info *node)
|
||||||
@@ -52,7 +37,7 @@ mark_node_registered(device_node_info *node)
|
|||||||
status_t res;
|
status_t res;
|
||||||
|
|
||||||
TRACE(("mark_node_registered(%p)\n", node));
|
TRACE(("mark_node_registered(%p)\n", node));
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
if (node->parent && !node->parent->registered) {
|
if (node->parent && !node->parent->registered) {
|
||||||
@@ -65,15 +50,15 @@ mark_node_registered(device_node_info *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
// check whether device is redetected and remove
|
/** Checks whether the device is redetected and removes any other
|
||||||
// any device that is on same connection.
|
* device that is on same connection and has the same device identifier.
|
||||||
// *redetected is set true if device is already registered;
|
* \a redetected is set true if device is already registered;
|
||||||
// the node must not yet be linked into parent node's children list
|
* the node must not yet be linked into parent node's children list
|
||||||
|
*/
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
is_device_redetected(device_node_info *node, device_node_info *parent, bool *redetected)
|
is_device_redetected(device_node_info *node, device_node_info *parent, bool *redetected)
|
||||||
@@ -94,7 +79,7 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we keep the lock very long, but this is the only way to be sure that
|
// we keep the lock very long, but this is the only way to be sure that
|
||||||
// noone else (un)-registers a conflicting note during the tests
|
// no one else (un)-registers a conflicting note during the tests
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -203,10 +188,10 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
|
|||||||
|
|
||||||
if (unregister_sibling) {
|
if (unregister_sibling) {
|
||||||
// increase ref_count to make sure node still exists
|
// increase ref_count to make sure node still exists
|
||||||
// when node_lock has been released
|
// when gNodeLock has been released
|
||||||
++sibling->ref_count;
|
++sibling->ref_count;
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
pnp_unregister_device(sibling);
|
pnp_unregister_device(sibling);
|
||||||
pnp_remove_node_ref_nolock(sibling);
|
pnp_remove_node_ref_nolock(sibling);
|
||||||
} else
|
} else
|
||||||
@@ -214,283 +199,184 @@ is_device_redetected(device_node_info *node, device_node_info *parent, bool *red
|
|||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// postpone searching for consumers if necessary
|
static status_t
|
||||||
// return: true, if postponed
|
push_node_on_stack(struct list *list, device_node_info *node)
|
||||||
|
|
||||||
static bool
|
|
||||||
pnp_postpone_probing(device_node_info *node)
|
|
||||||
{
|
{
|
||||||
benaphore_lock(&gNodeLock);
|
struct node_entry *entry = (struct node_entry *)malloc(sizeof(struct node_entry));
|
||||||
|
if (entry == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
// ask parent(!) if probing is to be postponed
|
dm_get_node_nolock(node);
|
||||||
if (node->parent == NULL || !node->parent->defer_probing) {
|
entry->node = node;
|
||||||
benaphore_unlock(&gNodeLock);
|
list_add_item(list, entry);
|
||||||
return false;
|
return B_OK;
|
||||||
}
|
|
||||||
|
|
||||||
// yes: this happens if the new node is a child of a bus node whose
|
|
||||||
// rescan has not been finished
|
|
||||||
TRACE(("postpone probing of node %p\n", node));
|
|
||||||
|
|
||||||
ADD_DL_LIST_HEAD(node, node->parent->unprobed_children, unprobed_ );
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public: register device node.
|
static device_node_info *
|
||||||
// in terms of I/O resources: if registration fails, they are freed; reason is
|
pop_node_from_stack(struct list *list)
|
||||||
// that they may have been transferred to node before error and back-transferring
|
{
|
||||||
// them would be complicated
|
device_node_info *node;
|
||||||
|
|
||||||
|
struct node_entry *entry = (struct node_entry *)list_remove_head_item(list);
|
||||||
|
if (entry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = entry->node;
|
||||||
|
free(entry);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
// Public functions part of the module API
|
||||||
|
|
||||||
|
|
||||||
|
/** Register device node.
|
||||||
|
* In terms of I/O resources: if registration fails, they are freed; reason is
|
||||||
|
* that they may have been transferred to node before error and back-transferring
|
||||||
|
* them would be complicated.
|
||||||
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_register_device(device_node_handle parent, const device_attr *attrs,
|
dm_register_node(device_node_handle parent, const device_attr *attrs,
|
||||||
const io_resource_handle *io_resources, device_node_handle *node)
|
const io_resource_handle *ioResources, device_node_handle *_node)
|
||||||
{
|
{
|
||||||
device_node_info *node_inf;
|
device_node_info *newNode;
|
||||||
bool redetected;
|
char *driverName = NULL;
|
||||||
status_t res = B_OK;
|
status_t status = B_OK;
|
||||||
|
struct list stack;
|
||||||
|
|
||||||
res = pnp_alloc_node(attrs, io_resources, &node_inf);
|
status = dm_allocate_node(attrs, ioResources, &newNode);
|
||||||
if (res != B_OK)
|
if (status != B_OK) {
|
||||||
goto err;
|
// always "consume" I/O resources
|
||||||
|
dm_release_io_resources(ioResources);
|
||||||
{
|
return status;
|
||||||
char *driver_name, *type;
|
|
||||||
|
|
||||||
if (pnp_get_attr_string(node_inf, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK) {
|
|
||||||
dprintf("Missing driver filename in node\n");
|
|
||||||
res = B_BAD_VALUE;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pnp_get_attr_string(node_inf, PNP_DRIVER_TYPE, &type, false) != B_OK) {
|
|
||||||
dprintf("Missing type in node registered by %s\n", driver_name);
|
|
||||||
|
|
||||||
free(driver_name);
|
|
||||||
res = B_BAD_VALUE;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE(("driver: %s, type: %s\n", driver_name, type));
|
|
||||||
|
|
||||||
free(driver_name);
|
|
||||||
free(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether this device already existed and thus is redetected
|
if (pnp_get_attr_string(newNode, B_DRIVER_MODULE, &driverName, false) != B_OK)
|
||||||
res = is_device_redetected(node_inf, parent, &redetected);
|
status = B_BAD_VALUE;
|
||||||
if (res != B_OK)
|
|
||||||
goto err1;
|
|
||||||
|
|
||||||
if (redetected) {
|
TRACE(("dm_register_node(driver = %s)\n", driverName));
|
||||||
// upon redetect, resources are released instead of transferred and
|
|
||||||
// no node is returned
|
free(driverName);
|
||||||
*node = NULL;
|
|
||||||
res = B_OK;
|
if (status != B_OK) {
|
||||||
goto err1;
|
dprintf("device_manager: Missing driver module name.\n");
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// transfer resources to device, unregistering all colliding devices;
|
// transfer resources to device, unregistering all colliding devices;
|
||||||
// this cannot fail - we've already allocated the resource handle array
|
// this cannot fail - we've already allocated the resource handle array
|
||||||
pnp_assign_io_resources(node_inf, io_resources);
|
dm_assign_io_resources(newNode, ioResources);
|
||||||
|
|
||||||
pnp_create_node_links(node_inf, parent);
|
|
||||||
|
|
||||||
// make it public
|
// make it public
|
||||||
res = mark_node_registered(node_inf);
|
dm_add_child_node(parent, newNode);
|
||||||
if (res != B_OK)
|
|
||||||
goto err2;
|
|
||||||
|
|
||||||
// from now on, node won't get freed as ref_count has been increased by registration
|
// The following is done to reduce the stack usage of deeply nested
|
||||||
|
// child device nodes.
|
||||||
|
// There is no other need to delay the complete registration process
|
||||||
|
// the way done here. This approach is also slightly different as
|
||||||
|
// the registration might fail later than it used in case of errors.
|
||||||
|
|
||||||
// check whether searching for consumers should be deferred
|
if (parent == NULL || parent->registered) {
|
||||||
if (pnp_postpone_probing(node_inf)) {
|
// register all device nodes not yet registered - build a list
|
||||||
// return without decrementing ref_count - else node may get
|
// that contain all of them, and then empty it one by one (during
|
||||||
// lost before deferred probe
|
// iteration, there might be new nodes added)
|
||||||
*node = node_inf;
|
|
||||||
return B_OK;
|
device_node_info *node = newNode;
|
||||||
|
|
||||||
|
list_init(&stack);
|
||||||
|
push_node_on_stack(&stack, newNode);
|
||||||
|
|
||||||
|
while ((node = pop_node_from_stack(&stack)) != NULL) {
|
||||||
|
device_node_info *child = NULL;
|
||||||
|
|
||||||
|
// register all fixed child device nodes as well
|
||||||
|
status = dm_register_fixed_child_devices(node);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
node->registered = true;
|
||||||
|
|
||||||
|
// and now let it register all child devices, if it's a bus
|
||||||
|
status = dm_register_child_devices(node);
|
||||||
|
if (status != B_OK)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
// push all new nodes on the stack
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
|
while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
|
||||||
|
if (!child->registered)
|
||||||
|
push_node_on_stack(&stack, child);
|
||||||
|
}
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
|
dm_put_node(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = pnp_initial_scan(node_inf);
|
if (_node)
|
||||||
if (res != B_OK)
|
*_node = newNode;
|
||||||
goto err2;
|
|
||||||
|
|
||||||
pnp_load_driver_automatically(node_inf, false);
|
return B_OK;
|
||||||
|
|
||||||
*node = node_inf;
|
|
||||||
|
|
||||||
TRACE(("done: node=%p\n", *node));
|
|
||||||
|
|
||||||
// alloc_node has set ref_count to one for safety, correct this now
|
|
||||||
pnp_remove_node_ref(node_inf);
|
|
||||||
return res;
|
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
// use this exit after i/o resources have been transferred to node
|
{
|
||||||
pnp_remove_node_ref(node_inf);
|
// nodes popped from the stack also need their reference count released
|
||||||
return res;
|
device_node_info *node;
|
||||||
|
while ((node = pop_node_from_stack(&stack)) != NULL) {
|
||||||
err1:
|
dm_put_node(node);
|
||||||
// alloc_node has set ref_count to one for safety, correct this now
|
}
|
||||||
pnp_remove_node_ref(node_inf);
|
}
|
||||||
err:
|
err:
|
||||||
// always "consume" i/o resources
|
// this also releases the I/O resources
|
||||||
pnp_release_io_resources(io_resources);
|
dm_put_node(newNode);
|
||||||
return res;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public: unregister device node
|
/** Unregister device node.
|
||||||
|
* This also makes sure that all children of this node are unregistered.
|
||||||
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
pnp_unregister_device(device_node_info *node)
|
dm_unregister_node(device_node_info *node)
|
||||||
{
|
{
|
||||||
device_node_info *dependency_list = NULL;
|
device_node_info *child, *nextChild;
|
||||||
|
|
||||||
TRACE(("pnp_unregister_device(%p)\n", node));
|
TRACE(("pnp_unregister_device(%p)\n", node));
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
// unregistered node and all children
|
// unregistered node and all children
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
pnp_unregister_node_rec(node, &dependency_list);
|
if (node->parent != NULL)
|
||||||
|
list_remove_item(&node->parent->children, node);
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
pnp_unload_driver_automatically(node, false);
|
// tell driver about their unregistration
|
||||||
|
dm_notify_unregistration(node);
|
||||||
|
|
||||||
// tell drivers about their unregistration
|
// unregister children recursively
|
||||||
pnp_notify_unregistration(dependency_list);
|
for (child = list_get_first_item(&node->children); child; child = nextChild) {
|
||||||
|
nextChild = (device_node_info *)child->siblings.next;
|
||||||
|
dm_unregister_node(child);
|
||||||
|
}
|
||||||
|
|
||||||
// now, we can safely decrease ref_count of unregistered nodes
|
dm_put_node(node);
|
||||||
pnp_unref_unregistered_nodes(dependency_list);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// remove <registered> flag of node and all children.
|
|
||||||
// list of all unregistered nodes is appended to <dependency_list>;
|
|
||||||
// (node_lock must be hold)
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_unregister_node_rec(device_node_info *node, device_node_info **dependency_list)
|
|
||||||
{
|
|
||||||
device_node_info *child, *next_child;
|
|
||||||
|
|
||||||
TRACE(("pnp_unregister_node_rec(%p)\n", node));
|
|
||||||
|
|
||||||
{
|
|
||||||
const char *driver_name, *type;
|
|
||||||
|
|
||||||
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK) {
|
|
||||||
dprintf("unregister_node: Missing driver filename in node\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_TYPE, &type, false) != B_OK) {
|
|
||||||
dprintf("unregister_node: Missing type in node registered by %s\n", driver_name);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE(("driver: %s, type: %s\n", driver_name, type));
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
// especially when we go through children, it can happen that they
|
|
||||||
// got unregistered already, so ignore them silently
|
|
||||||
if (!node->registered)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TRACE(("Preparing unregistration\n"));
|
|
||||||
|
|
||||||
node->registered = false;
|
|
||||||
ADD_DL_LIST_HEAD(node, *dependency_list, notify_);
|
|
||||||
|
|
||||||
// unregister children recursively
|
|
||||||
for (child = node->children; child; child = next_child) {
|
|
||||||
next_child = child->siblings_next;
|
|
||||||
pnp_unregister_node_rec(child, dependency_list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// defer probing of children.
|
|
||||||
// node_lock must be hold
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_defer_probing_of_children_nolock(device_node_info *node)
|
|
||||||
{
|
|
||||||
++node->defer_probing;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// defer probing of children
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_defer_probing_of_children(device_node_info *node)
|
|
||||||
{
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
pnp_defer_probing_of_children_nolock(node);
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// execute deferred probing of children
|
|
||||||
// (node_lock must be hold)
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_probe_waiting_children_nolock(device_node_info *node)
|
|
||||||
{
|
|
||||||
if (--node->defer_probing > 0 && node->unprobed_children != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TRACE(("execute deferred probing of parent %p\n", node));
|
|
||||||
|
|
||||||
while (node->unprobed_children) {
|
|
||||||
device_node_info *child = node->unprobed_children;
|
|
||||||
|
|
||||||
REMOVE_DL_LIST(child, node->unprobed_children, unprobed_);
|
|
||||||
|
|
||||||
// child may have been removed meanwhile
|
|
||||||
if (child->registered) {
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
if (pnp_initial_scan(child) == B_OK)
|
|
||||||
pnp_load_driver_automatically(node, false);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reference count was increment to keep node alive in wannabe list;
|
|
||||||
// this is not necessary anymore
|
|
||||||
pnp_remove_node_ref(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE((".. done.\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// execute deferred probing of children
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_probe_waiting_children(device_node_info *node)
|
|
||||||
{
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
pnp_probe_waiting_children_nolock(node);
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,154 +29,44 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define PNP_ROOT_TYPE_NAME "pnp/root"
|
#define PNP_ROOT_MODULE_NAME "system/devices_root/driver_v1"
|
||||||
// type of pnp root device
|
|
||||||
|
|
||||||
#define PNP_ROOT_DRIVERS_DIR "root"
|
|
||||||
// registration directory of pnp root drivers
|
|
||||||
// (put all drivers under "universal" and use unique connection names)
|
|
||||||
|
|
||||||
#define PNP_ROOT_MODULE_NAME "sys/pnp_root/v1"
|
|
||||||
|
|
||||||
|
|
||||||
static device_node_handle sRootNode;
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pnp_root_init_root(void)
|
dm_init_root_node(void)
|
||||||
{
|
{
|
||||||
device_attr attrs[] = {
|
device_attr attrs[] = {
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: PNP_ROOT_TYPE_NAME }},
|
{ B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "Devices Root" }},
|
||||||
|
|
||||||
// well - connection is actually pointless as there is no other root node
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "pnp_root" }},
|
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "pnp_root" }},
|
|
||||||
|
|
||||||
// directory for root drivers
|
|
||||||
// ToDo: temporary hack to get things started!
|
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: "bus_managers/isa/root" }},
|
|
||||||
{ PNP_DRIVER_DYNAMIC_CONSUMER, B_STRING_TYPE, { string: PNP_ROOT_DRIVERS_DIR "/" }},
|
|
||||||
|
|
||||||
|
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "root" }},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (pnp_register_device(NULL, attrs, NULL, &sRootNode) != B_OK)
|
if (dm_register_node(NULL, attrs, NULL, &gRootNode) != B_OK) {
|
||||||
dprintf("Cannot register PnP-Root\n");
|
// ToDo: don't panic for now
|
||||||
// ToDo: don't panic for now
|
dprintf("Cannot register Devices Root Node\n");
|
||||||
// panic("Cannot register PnP-Root\n");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_root_destroy_root(void)
|
|
||||||
{
|
|
||||||
// make sure we are registered
|
|
||||||
if (sRootNode == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TRACE(("Destroying PnP-root\n"));
|
|
||||||
|
|
||||||
if (pnp_unregister_device(sRootNode) != B_OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sRootNode = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
pnp_root_rescan_root(void)
|
|
||||||
{
|
|
||||||
// make sure we are registered
|
|
||||||
if (sRootNode == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TRACE(("Rescanning PnP-root\n"));
|
|
||||||
|
|
||||||
// scan _very_ deep
|
|
||||||
pnp_rescan(sRootNode, 30000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pnp_root_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
root_init_driver(device_node_handle node, void *user_cookie, void **_cookie)
|
||||||
{
|
{
|
||||||
*cookie = NULL;
|
*_cookie = NULL;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
pnp_root_uninit_device(void *cookie)
|
root_uninit_driver(void *cookie)
|
||||||
{
|
{
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
static status_t pnp_root_device_added(
|
|
||||||
device_node_handle parent )
|
|
||||||
{
|
|
||||||
char *tmp;
|
|
||||||
status_t res;
|
|
||||||
device_node_handle loader_node;
|
|
||||||
|
|
||||||
// make sure parent is really root
|
|
||||||
if( pnp->get_attr_string( parent, PNP_DRIVER_TYPE, &tmp, false ))
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if( strcmp( tmp, PNP_ROOT_NODE_TYPE_NAME ) != 0 ) {
|
|
||||||
free( tmp );
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
free( tmp );
|
|
||||||
|
|
||||||
// load ISA bus manager
|
|
||||||
// if you don't want ISA, remove this registration
|
|
||||||
{
|
|
||||||
device_attr attrs[] = {
|
|
||||||
// info about ourself
|
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: "pnp/isa_loader" }},
|
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: ISA2_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "ISA" }},
|
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "ISA" }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
SHOW_FLOW0( 4, "registering ISA root" );
|
|
||||||
|
|
||||||
res = pnp->register_device( parent, attrs, NULL, &loader_node );
|
|
||||||
if( res != B_OK )
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// load PCI bus manager
|
|
||||||
{
|
|
||||||
device_attr attrs[] = {
|
|
||||||
// info about ourself
|
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: "pnp/pci_loader" }},
|
|
||||||
{ PNP_DRIVER_FIXED_CONSUMER, B_STRING_TYPE, { string: PCI_ROOT_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "PCI" }},
|
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "PCI" }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
SHOW_FLOW0( 4, "registering PCI root" );
|
|
||||||
|
|
||||||
res = pnp->register_device( parent, attrs, NULL, &loader_node );
|
|
||||||
if( res != B_OK )
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
std_ops(int32 op, ...)
|
root_std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case B_MODULE_INIT:
|
case B_MODULE_INIT:
|
||||||
@@ -193,12 +83,13 @@ driver_module_info gDeviceRootModule = {
|
|||||||
{
|
{
|
||||||
PNP_ROOT_MODULE_NAME,
|
PNP_ROOT_MODULE_NAME,
|
||||||
0,
|
0,
|
||||||
std_ops,
|
root_std_ops,
|
||||||
},
|
},
|
||||||
|
|
||||||
pnp_root_init_device,
|
NULL, // supported devices
|
||||||
pnp_root_uninit_device,
|
NULL, // register device
|
||||||
NULL,
|
root_init_driver,
|
||||||
|
root_uninit_driver,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,9 @@
|
|||||||
#include "device_manager_private.h"
|
#include "device_manager_private.h"
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
#define TRACE_SCAN
|
#define TRACE_SCAN
|
||||||
@@ -31,284 +33,68 @@
|
|||||||
# define TRACE(x) ;
|
# define TRACE(x) ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static status_t scan(device_node_info *node, bool rescan);
|
||||||
|
|
||||||
/** public function: rescan PnP node */
|
|
||||||
|
|
||||||
status_t
|
static int32 sRescanning = 0;
|
||||||
pnp_rescan(device_node_info *node, uint32 depth)
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// execute deferred probing of children
|
||||||
|
// (node_lock must be hold)
|
||||||
|
|
||||||
|
void
|
||||||
|
pnp_probe_waiting_children_nolock(device_node_info *node)
|
||||||
{
|
{
|
||||||
return pnp_rescan_int(node, depth, false);
|
TRACE(("execute deferred probing of parent %p\n", node));
|
||||||
|
|
||||||
|
while (node->unprobed_children) {
|
||||||
|
device_node_info *child = node->unprobed_children;
|
||||||
|
|
||||||
|
REMOVE_DL_LIST(child, node->unprobed_children, unprobed_);
|
||||||
|
|
||||||
|
// child may have been removed meanwhile
|
||||||
|
if (child->registered) {
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
|
if (pnp_initial_scan(child) == B_OK)
|
||||||
|
pnp_load_driver_automatically(node, false);
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reference count was increment to keep node alive in wannabe list;
|
||||||
|
// this is not necessary anymore
|
||||||
|
pnp_remove_node_ref(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE((".. done.\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** execute registration of fully constructed node */
|
// execute deferred probing of children
|
||||||
|
|
||||||
status_t
|
void
|
||||||
pnp_initial_scan(device_node_info *node)
|
pnp_probe_waiting_children(device_node_info *node)
|
||||||
{
|
{
|
||||||
pnp_start_hook_call(node);
|
|
||||||
|
|
||||||
node->init_finished = true;
|
|
||||||
|
|
||||||
pnp_finish_hook_call(node);
|
|
||||||
|
|
||||||
return pnp_rescan_int(node, 1, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** check whether rescanning a node makes sense in terms of
|
|
||||||
* double scans.
|
|
||||||
* node_lock must be hold
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool
|
|
||||||
is_rescan_sensible(device_node_info *node)
|
|
||||||
{
|
|
||||||
uint depth;
|
|
||||||
device_node_info *child;
|
|
||||||
|
|
||||||
TRACE(("is_rescan_sensible(node: %p)\n", node));
|
|
||||||
|
|
||||||
// if a child is being scanned, abort our rescan to avoid
|
|
||||||
// concurrent scans by the same driver on the same device
|
|
||||||
for (child = node->children; child != NULL; child = child->siblings_next) {
|
|
||||||
if (child->rescan_depth > 0) {
|
|
||||||
TRACE(("child %p is being scanned\n", child));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE(("check parents\n"));
|
|
||||||
|
|
||||||
// make sure neither this nor parent node is scanned recursively
|
|
||||||
// up to this node as this would lead to unnecessary double-scans
|
|
||||||
// (don't need to check whether parent is unregistered as
|
|
||||||
// all children would have been unregistered immediately)
|
|
||||||
for (depth = 1; node != NULL; node = node->parent, ++depth) {
|
|
||||||
if (node->rescan_depth >= depth) {
|
|
||||||
TRACE(("parent %p is being scanned", node));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** mark children of node as being scanned.
|
|
||||||
* children that have their drivers loaded are not
|
|
||||||
* scanned unless they allow that explicitely.
|
|
||||||
* node_lock must be hold
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
mark_children_scanned(device_node_info *node)
|
|
||||||
{
|
|
||||||
device_node_info *child, *next_child;
|
|
||||||
|
|
||||||
TRACE(("mark_children_scanned()\n"));
|
|
||||||
|
|
||||||
for (child = node->children; child != NULL; child = next_child) {
|
|
||||||
uint8 never_rescan, no_live_rescan;
|
|
||||||
|
|
||||||
next_child = child->siblings_next;
|
|
||||||
|
|
||||||
// ignore dead children
|
|
||||||
if (!child->registered)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// check whether device can be rescanned at all
|
|
||||||
if (pnp_get_attr_uint8_nolock(child, PNP_DRIVER_NEVER_RESCAN,
|
|
||||||
&never_rescan, false) == B_OK && never_rescan) {
|
|
||||||
TRACE(("no rescan allowed on device %p\n", child));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pnp_get_attr_uint8_nolock(child, PNP_DRIVER_NO_LIVE_RESCAN,
|
|
||||||
&no_live_rescan, false) != B_OK)
|
|
||||||
no_live_rescan = false;
|
|
||||||
|
|
||||||
if (no_live_rescan) {
|
|
||||||
TRACE(("no life rescan allowed on device %p\n", child));
|
|
||||||
|
|
||||||
if (child->load_count + child->loading > 0) {
|
|
||||||
TRACE(("device %p loaded - skipping it\n", child));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
child->blocked_by_rescan = true;
|
|
||||||
++child->load_block_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
child->verifying = true;
|
|
||||||
child->redetected = false;
|
|
||||||
|
|
||||||
// unload driver during rescan if needed
|
|
||||||
// (need to lock next_child temporarily as we release node_lock)
|
|
||||||
if (next_child)
|
|
||||||
++next_child->ref_count;
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
pnp_unload_driver_automatically(child, true);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
if (next_child)
|
|
||||||
pnp_remove_node_ref_nolock(next_child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** stop children verification, resetting associated flag and unblocking loads. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
reset_children_verification(device_node_info *node)
|
|
||||||
{
|
|
||||||
device_node_info *child, *next_child;
|
|
||||||
|
|
||||||
TRACE(("reset_children_verification()\n"));
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
for (child = node->children; child != NULL; child = next_child) {
|
pnp_probe_waiting_children_nolock(node);
|
||||||
next_child = child->siblings_next;
|
|
||||||
|
|
||||||
if (!child->verifying)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
child->verifying = false;
|
|
||||||
|
|
||||||
if (child->blocked_by_rescan) {
|
|
||||||
child->blocked_by_rescan = false;
|
|
||||||
pnp_unblock_load(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_child)
|
|
||||||
++next_child->ref_count;
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
pnp_load_driver_automatically(node, true);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
if (next_child)
|
|
||||||
pnp_remove_node_ref_nolock(next_child);
|
|
||||||
}
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
/** unregister child nodes that weren't detected anymore */
|
|
||||||
|
|
||||||
static void
|
|
||||||
unregister_lost_children(device_node_info *node)
|
|
||||||
{
|
|
||||||
device_node_info *child, *dependency_list;
|
|
||||||
|
|
||||||
TRACE(("unregister_lost_children()\n"));
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
for (child = node->children, dependency_list = NULL; child != NULL;
|
|
||||||
child = child->siblings_next) {
|
|
||||||
if (child->verifying && !child->redetected) {
|
|
||||||
TRACE(("removing lost device %p\n", child));
|
|
||||||
// child wasn't detected anymore - put it onto remove list
|
|
||||||
pnp_unregister_node_rec(child, &dependency_list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
// finish verification of children
|
|
||||||
// (must be done now to unblock them;
|
|
||||||
// else we risk deadlocks during notification)
|
|
||||||
reset_children_verification(node);
|
|
||||||
|
|
||||||
// inform all drivers of unregistered nodes
|
|
||||||
pnp_notify_unregistration(dependency_list);
|
|
||||||
|
|
||||||
// now, we can safely decrease ref_count of unregistered nodes
|
|
||||||
pnp_unref_unregistered_nodes(dependency_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** recursively scan children of node (using depth-scan).
|
|
||||||
* node_lock must be hold
|
|
||||||
*/
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
recursive_scan(device_node_info *node, uint depth)
|
|
||||||
{
|
|
||||||
device_node_info *child, *next_child;
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
TRACE(("recursive_scan(node: %p, depth=%d)\n", node, depth));
|
|
||||||
|
|
||||||
child = node->children;
|
|
||||||
|
|
||||||
// the child we want to access must be locked
|
|
||||||
if (child != NULL)
|
|
||||||
++child->ref_count;
|
|
||||||
|
|
||||||
for (; child != NULL; child = next_child) {
|
|
||||||
next_child = child->siblings_next;
|
|
||||||
|
|
||||||
// lock next child, so its node is still valid after rescan
|
|
||||||
if (next_child != NULL)
|
|
||||||
++next_child->ref_count;
|
|
||||||
|
|
||||||
// during rescan, we must release node_lock to not deadlock
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
res = pnp_rescan(child, depth - 1);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
// unlock current child as it's not accessed anymore
|
|
||||||
pnp_remove_node_ref_nolock(child);
|
|
||||||
|
|
||||||
// ignore errors because of touching unregistered nodes
|
|
||||||
if (res != B_OK && res != B_NAME_NOT_FOUND)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no need unlock last child (don't be loop already)
|
|
||||||
TRACE(("recursive_scan(): done\n"));
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (next_child != NULL)
|
|
||||||
pnp_remove_node_ref_nolock(next_child);
|
|
||||||
|
|
||||||
TRACE(("recursive_scan(): failed\n"));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** ask bus to (re-)scan for connected devices */
|
/** ask bus to (re-)scan for connected devices */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rescan_bus(device_node_info *node)
|
scan_bus(device_node_info *node, bool rescan)
|
||||||
{
|
{
|
||||||
// busses can register their children themselves
|
// busses can register their children themselves
|
||||||
bus_module_info *interface;
|
bus_module_info *interface;
|
||||||
void *cookie;
|
void *cookie;
|
||||||
bool defer_probe;
|
|
||||||
uint8 defer_probe_var;
|
|
||||||
|
|
||||||
// delay children probing if requested
|
|
||||||
defer_probe = pnp_get_attr_uint8(node,
|
|
||||||
PNP_BUS_DEFER_PROBE, &defer_probe_var, false ) == B_OK
|
|
||||||
&& defer_probe_var != 0;
|
|
||||||
|
|
||||||
if (defer_probe) {
|
|
||||||
TRACE(("defer probing for consumers\n"));
|
|
||||||
pnp_defer_probing_of_children(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load driver during rescan
|
// load driver during rescan
|
||||||
pnp_load_driver(node, NULL, (driver_module_info **)&interface, &cookie);
|
pnp_load_driver(node, NULL, (driver_module_info **)&interface, &cookie);
|
||||||
@@ -320,127 +106,131 @@ rescan_bus(device_node_info *node)
|
|||||||
// concurrently has been assured to not happen)
|
// concurrently has been assured to not happen)
|
||||||
pnp_start_hook_call(node);
|
pnp_start_hook_call(node);
|
||||||
|
|
||||||
if (interface->rescan != NULL)
|
if (rescan) {
|
||||||
interface->rescan(cookie);
|
if (interface->rescan_bus != NULL)
|
||||||
|
interface->rescan_bus(cookie);
|
||||||
|
} else {
|
||||||
|
if (interface->register_child_devices != NULL)
|
||||||
|
interface->register_child_devices(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
pnp_finish_hook_call(node);
|
pnp_finish_hook_call(node);
|
||||||
|
|
||||||
pnp_unload_driver(node);
|
pnp_unload_driver(node);
|
||||||
|
|
||||||
// time to execute delayed probing
|
// time to execute delayed probing
|
||||||
if (defer_probe)
|
// pnp_probe_waiting_children(node);
|
||||||
pnp_probe_waiting_children(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** rescan for consumers
|
/** recursively scan children of node (using depth-scan).
|
||||||
* ignore_fixed_consumers - true, to leave fixed consumers alone
|
* node_lock must be hold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
status_t
|
static status_t
|
||||||
pnp_rescan_int(device_node_info *node, uint32 depth,
|
recursive_scan(device_node_info *node)
|
||||||
bool ignore_fixed_consumers)
|
|
||||||
{
|
{
|
||||||
bool is_bus;
|
device_node_info *child = NULL;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
TRACE(("recursive_scan(node = %p)\n", node));
|
||||||
|
|
||||||
|
while ((child = list_get_next_item(&node->children, child)) != NULL) {
|
||||||
|
dm_get_node_nolock(child);
|
||||||
|
|
||||||
|
// during rescan, we must release node_lock to not deadlock
|
||||||
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
|
status = scan(child, true);
|
||||||
|
|
||||||
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
|
// unlock current child as it's not accessed anymore
|
||||||
|
dm_put_node_nolock(child);
|
||||||
|
|
||||||
|
// ignore errors because of touching unregistered nodes
|
||||||
|
if (status != B_OK && status != B_NAME_NOT_FOUND)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need unlock last child (don't be loop already)
|
||||||
|
TRACE(("recursive_scan(): done\n"));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** (re)scan for child nodes
|
||||||
|
*/
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
scan(device_node_info *node, bool rescan)
|
||||||
|
{
|
||||||
|
status_t status = B_OK;
|
||||||
uint8 dummy;
|
uint8 dummy;
|
||||||
status_t res = B_OK;
|
bool isBus;
|
||||||
|
|
||||||
TRACE(("pnp_rescan_int(node: %p, depth = %ld)\n", node, depth));
|
TRACE(("scan(node = %p, mode: %s)\n", node, rescan ? "rescan" : "register"));
|
||||||
|
|
||||||
//pnp_load_boot_links();
|
isBus = pnp_get_attr_uint8(node, PNP_BUS_IS_BUS, &dummy, false) == B_OK;
|
||||||
|
|
||||||
// ignore depth 0 silently
|
|
||||||
if (depth == 0) {
|
|
||||||
res = B_OK;
|
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_bus = pnp_get_attr_uint8(node, PNP_BUS_IS_BUS, &dummy, false) == B_OK;
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
// don't scan unregistered nodes
|
|
||||||
if (!node->registered) {
|
|
||||||
TRACE(("node not registered"));
|
|
||||||
res = B_NAME_NOT_FOUND;
|
|
||||||
goto err2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_rescan_sensible(node)) {
|
|
||||||
// somebody else does the rescan, so no need to report error
|
|
||||||
TRACE(("rescan not sensible\n"));
|
|
||||||
res = B_OK;
|
|
||||||
goto err2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark old devices
|
|
||||||
// exception: during registration, fixed consumers are
|
|
||||||
// initialized seperately, and we don't want to mark their node
|
|
||||||
// as being old
|
|
||||||
if (!ignore_fixed_consumers || is_bus)
|
|
||||||
mark_children_scanned(node);
|
|
||||||
|
|
||||||
// tell other scans what we are doing to avoid double scans
|
|
||||||
node->rescan_depth = depth;
|
|
||||||
|
|
||||||
// keep node alive
|
|
||||||
++node->ref_count;
|
|
||||||
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
// do the real thing - scan node
|
// do the real thing - scan node
|
||||||
if (is_bus)
|
if (!rescan) {
|
||||||
rescan_bus(node);
|
bool loadDriversLater = false;
|
||||||
|
char *deviceType = NULL;
|
||||||
|
pnp_get_attr_uint8(node, B_DRIVER_FIND_DEVICES_ON_DEMAND, &loadDriversLater, false);
|
||||||
|
pnp_get_attr_string(node, B_DRIVER_DEVICE_TYPE, &deviceType, false);
|
||||||
|
|
||||||
// ask possible consumers to register their nodes
|
if (isBus)
|
||||||
if (!ignore_fixed_consumers) {
|
scan_bus(node, false);
|
||||||
TRACE(("scan fixed consumers\n"));
|
|
||||||
|
|
||||||
res = pnp_notify_fixed_consumers(node);
|
// ask possible children to register their nodes
|
||||||
if (res != B_OK)
|
|
||||||
goto err;
|
if (!loadDriversLater && deviceType == NULL) {
|
||||||
|
status = dm_register_dynamic_child_devices(node);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(deviceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = pnp_notify_dynamic_consumers(node);
|
|
||||||
if (res != B_OK)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// unregister children that weren't detected anymore
|
|
||||||
unregister_lost_children(node);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
benaphore_lock(&gNodeLock);
|
||||||
|
|
||||||
// mark scan as being finished to not block recursive scans
|
|
||||||
node->rescan_depth = 0;
|
|
||||||
|
|
||||||
// scan children recursively;
|
// scan children recursively;
|
||||||
// keep the node_lock to make sure noone removes children meanwhile
|
// keep the node_lock to make sure noone removes children meanwhile
|
||||||
if (depth > 1)
|
if (rescan && isBus)
|
||||||
res = recursive_scan(node, depth);
|
status = recursive_scan(node);
|
||||||
|
|
||||||
pnp_remove_node_ref_nolock(node);
|
|
||||||
benaphore_unlock(&gNodeLock);
|
benaphore_unlock(&gNodeLock);
|
||||||
|
|
||||||
//pnp_unload_boot_links();
|
TRACE(("scan(): done (%p) - %s\n", node, strerror(status)));
|
||||||
|
return status;
|
||||||
TRACE(("pnp_rescan_int(): done (%p) - %s\n", node, strerror(res)));
|
|
||||||
return res;
|
|
||||||
|
|
||||||
err:
|
|
||||||
reset_children_verification(node);
|
|
||||||
|
|
||||||
benaphore_lock(&gNodeLock);
|
|
||||||
|
|
||||||
node->rescan_depth = 0;
|
|
||||||
pnp_remove_node_ref_nolock(node);
|
|
||||||
|
|
||||||
err2:
|
|
||||||
benaphore_unlock(&gNodeLock);
|
|
||||||
|
|
||||||
TRACE(("pnp_rescan_int(): failed (%p, %s)\n", node, strerror(res)));
|
|
||||||
|
|
||||||
err3:
|
|
||||||
//pnp_unload_boot_links();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
/** Rescan device node (only works if it's a bus) */
|
||||||
|
|
||||||
|
status_t
|
||||||
|
dm_rescan(device_node_info *node)
|
||||||
|
{
|
||||||
|
// only allow a single rescan at a time
|
||||||
|
if (atomic_add(&sRescanning, 1) > 0) {
|
||||||
|
atomic_add(&sRescanning, -1);
|
||||||
|
return B_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scan(node, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** execute registration of fully constructed node */
|
||||||
|
|
||||||
|
status_t
|
||||||
|
dm_register_child_devices(device_node_info *node)
|
||||||
|
{
|
||||||
|
return scan(node, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,37 +266,44 @@ devfs_find_in_dir(struct devfs_vnode *dir, const char *path)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *v)
|
devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *vnode)
|
||||||
{
|
{
|
||||||
if (!S_ISDIR(dir->stream.type))
|
if (!S_ISDIR(dir->stream.type))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
v->dir_next = dir->stream.u.dir.dir_head;
|
vnode->dir_next = dir->stream.u.dir.dir_head;
|
||||||
dir->stream.u.dir.dir_head = v;
|
dir->stream.u.dir.dir_head = vnode;
|
||||||
|
|
||||||
v->parent = dir;
|
vnode->parent = dir;
|
||||||
dir->modification_time = time(NULL);
|
dir->modification_time = time(NULL);
|
||||||
|
|
||||||
|
notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name, vnode->id);
|
||||||
|
notify_stat_changed(sDeviceFileSystem->id, dir->id, B_STAT_MODIFICATION_TIME);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *findit)
|
devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *removeNode)
|
||||||
{
|
{
|
||||||
struct devfs_vnode *v;
|
struct devfs_vnode *vnode = dir->stream.u.dir.dir_head;
|
||||||
struct devfs_vnode *last_v;
|
struct devfs_vnode *lastNode = NULL;
|
||||||
|
|
||||||
for (v = dir->stream.u.dir.dir_head, last_v = NULL; v; last_v = v, v = v->dir_next) {
|
for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) {
|
||||||
if (v == findit) {
|
if (vnode == removeNode) {
|
||||||
/* make sure all dircookies dont point to this vnode */
|
// make sure no dircookies point to this vnode
|
||||||
update_dircookies(dir, v);
|
update_dircookies(dir, vnode);
|
||||||
|
|
||||||
if (last_v)
|
if (lastNode)
|
||||||
last_v->dir_next = v->dir_next;
|
lastNode->dir_next = vnode->dir_next;
|
||||||
else
|
else
|
||||||
dir->stream.u.dir.dir_head = v->dir_next;
|
dir->stream.u.dir.dir_head = vnode->dir_next;
|
||||||
v->dir_next = NULL;
|
vnode->dir_next = NULL;
|
||||||
dir->modification_time = time(NULL);
|
dir->modification_time = time(NULL);
|
||||||
|
|
||||||
|
notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name, vnode->id);
|
||||||
|
notify_stat_changed(sDeviceFileSystem->id, dir->id, B_STAT_MODIFICATION_TIME);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -927,7 +934,7 @@ devfs_get_vnode(fs_volume _fs, vnode_id id, fs_vnode *_vnode, bool reenter)
|
|||||||
TRACE(("devfs_get_vnode: looked it up at %p\n", *_vnode));
|
TRACE(("devfs_get_vnode: looked it up at %p\n", *_vnode));
|
||||||
|
|
||||||
if (*_vnode)
|
if (*_vnode)
|
||||||
return 0;
|
return B_OK;
|
||||||
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
@@ -1535,7 +1542,7 @@ devfs_write_stat(fs_volume _fs, fs_vnode _vnode, const struct stat *stat, uint32
|
|||||||
|
|
||||||
mutex_unlock(&fs->lock);
|
mutex_unlock(&fs->lock);
|
||||||
|
|
||||||
notify_listener(B_STAT_CHANGED, fs->id, 0, 0, vnode->id, NULL);
|
notify_stat_changed(fs->id, vnode->id, statMask);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1626,15 +1633,11 @@ file_system_info gDeviceFileSystem = {
|
|||||||
// temporary hack to get it to work with the current device manager
|
// temporary hack to get it to work with the current device manager
|
||||||
|
|
||||||
|
|
||||||
static device_manager_info *pnp;
|
static device_manager_info *sDeviceManager;
|
||||||
|
|
||||||
|
|
||||||
static const device_attr pnp_devfs_attrs[] =
|
static const device_attr pnp_devfs_attrs[] = {
|
||||||
{
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
||||||
{ PNP_DRIVER_DRIVER, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
|
||||||
{ PNP_DRIVER_TYPE, B_STRING_TYPE, { string: "devfs_device_notifier" }},
|
|
||||||
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "devfs" }},
|
|
||||||
{ PNP_DRIVER_DEVICE_IDENTIFIER, B_STRING_TYPE, { string: "devfs" }},
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1644,20 +1647,13 @@ static const device_attr pnp_devfs_attrs[] =
|
|||||||
static status_t
|
static status_t
|
||||||
pnp_devfs_register_device(device_node_handle parent)
|
pnp_devfs_register_device(device_node_handle parent)
|
||||||
{
|
{
|
||||||
char *str = NULL, *filename = NULL;
|
char *filename = NULL;
|
||||||
device_node_handle node;
|
device_node_handle node;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
TRACE(("pnp_devfs_probe()\n"));
|
TRACE(("pnp_devfs_probe()\n"));
|
||||||
|
|
||||||
// make sure we can handle this parent
|
if (sDeviceManager->get_attr_string(parent, PNP_DEVFS_FILENAME, &filename, true) != B_OK) {
|
||||||
if (pnp->get_attr_string(parent, PNP_DRIVER_TYPE, &str, false) != B_OK
|
|
||||||
|| strcmp(str, PNP_DEVFS_TYPE_NAME) != 0) {
|
|
||||||
status = B_ERROR;
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pnp->get_attr_string(parent, PNP_DEVFS_FILENAME, &filename, true) != B_OK) {
|
|
||||||
dprintf("devfs: Item containing file name is missing\n");
|
dprintf("devfs: Item containing file name is missing\n");
|
||||||
status = B_ERROR;
|
status = B_ERROR;
|
||||||
goto err1;
|
goto err1;
|
||||||
@@ -1665,13 +1661,16 @@ pnp_devfs_register_device(device_node_handle parent)
|
|||||||
|
|
||||||
TRACE(("Adding %s\n", filename));
|
TRACE(("Adding %s\n", filename));
|
||||||
|
|
||||||
pnp_devfs_driver_info *info;
|
status = sDeviceManager->register_device(parent, pnp_devfs_attrs, NULL, &node);
|
||||||
status = pnp->load_driver(parent, NULL, (driver_module_info **)&info, NULL);
|
if (status != B_OK || node == NULL)
|
||||||
if (status != B_OK)
|
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
status = pnp->register_device(parent, pnp_devfs_attrs, NULL, &node);
|
// ToDo: this is a hack to get things working (init_driver() only works for registered nodes)
|
||||||
if (status != B_OK || node == NULL)
|
parent->registered = true;
|
||||||
|
|
||||||
|
pnp_devfs_driver_info *info;
|
||||||
|
status = sDeviceManager->init_driver(parent, NULL, (driver_module_info **)&info, NULL);
|
||||||
|
if (status != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
//add_device(device);
|
//add_device(device);
|
||||||
@@ -1683,11 +1682,10 @@ pnp_devfs_register_device(device_node_handle parent)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err3:
|
err3:
|
||||||
pnp->unregister_device(node);
|
sDeviceManager->uninit_driver(parent);
|
||||||
err2:
|
err2:
|
||||||
pnp->unload_driver(parent);
|
sDeviceManager->unregister_device(node);
|
||||||
err1:
|
err1:
|
||||||
free(str);
|
|
||||||
free(filename);
|
free(filename);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -1728,9 +1726,9 @@ pnp_devfs_device_removed(device_node_handle node, void *cookie)
|
|||||||
#endif
|
#endif
|
||||||
TRACE(("pnp_devfs_device_removed()\n"));
|
TRACE(("pnp_devfs_device_removed()\n"));
|
||||||
#if 0
|
#if 0
|
||||||
parent = pnp->get_parent(node);
|
parent = sDeviceManager->get_parent(node);
|
||||||
|
|
||||||
// don't use cookie - we don't use pnp loading scheme but
|
// don't use cookie - we don't use sDeviceManager loading scheme but
|
||||||
// global data and keep care of everything ourself!
|
// global data and keep care of everything ourself!
|
||||||
ACQUIRE_BEN( &device_list_lock );
|
ACQUIRE_BEN( &device_list_lock );
|
||||||
|
|
||||||
@@ -1738,9 +1736,9 @@ pnp_devfs_device_removed(device_node_handle node, void *cookie)
|
|||||||
if( device->parent == parent )
|
if( device->parent == parent )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( device != NULL ) {
|
if( device != NULL ) {
|
||||||
pnp_devfs_remove_device( device );
|
pnp_devfs_remove_device(device);
|
||||||
} else {
|
} else {
|
||||||
SHOW_ERROR( 0, "bug: node %p couldn't been found", node );
|
SHOW_ERROR( 0, "bug: node %p couldn't been found", node );
|
||||||
res = B_NAME_NOT_FOUND;
|
res = B_NAME_NOT_FOUND;
|
||||||
@@ -1758,10 +1756,10 @@ pnp_devfs_std_ops(int32 op, ...)
|
|||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case B_MODULE_INIT:
|
case B_MODULE_INIT:
|
||||||
return get_module(DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp);
|
return get_module(B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager);
|
||||||
|
|
||||||
case B_MODULE_UNINIT:
|
case B_MODULE_UNINIT:
|
||||||
put_module(DEVICE_MANAGER_MODULE_NAME);
|
put_module(B_DEVICE_MANAGER_MODULE_NAME);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1777,10 +1775,13 @@ driver_module_info gDeviceForDriversModule = {
|
|||||||
pnp_devfs_std_ops
|
pnp_devfs_std_ops
|
||||||
},
|
},
|
||||||
|
|
||||||
NULL,
|
NULL, // supports device
|
||||||
NULL,
|
|
||||||
pnp_devfs_register_device,
|
pnp_devfs_register_device,
|
||||||
pnp_devfs_device_removed
|
NULL, // init driver
|
||||||
|
NULL, // uninit driver
|
||||||
|
pnp_devfs_device_removed,
|
||||||
|
NULL, // cleanup
|
||||||
|
NULL, // get paths
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user