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