* Integration of the new driver architecture.

* Moved devfs from fs/ to device_manager/, and separated the legacy driver
  support from it.
* Removed fast_log module.
* There are a couple of (temporary) regressions, though:
  - legacy SATA and ISA IDE support is disabled, the drivers haven't been
    ported yet.
  - The not yet used ATA bus manager hasn't been ported yet, either.
  - AHCI changes have not been tested.
  - the listdev command has been removed from the build (as it currently
    doesn't work anymore).
  - device manager generated IDs currently are not freed anymore when a device
    node is removed.
  - generic drivers can't yet use the new driver architecture.
  - simple busses that do not support device types won't work yet.
  - legacy driver publishing/unpublishing (ie. what USB needs) has not been
    tested, and may be broken.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25662 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-05-26 16:52:27 +00:00
parent 113a13d83e
commit 368167ede8
85 changed files with 5993 additions and 7276 deletions
+8 -8
View File
@@ -33,7 +33,7 @@ BEOS_BIN = "[" addattr alert arp base64 basename bc beep bootman bzip2 cal cat
funzip #fwcontrol
gawk $(X86_ONLY)gdb grep groups gzip gzexe hd head hey hostname id ident
ideinfo idestatus ifconfig <bin>install installsound iroster isvolume join
keymap kill less lessecho lesskey link listarea listattr listdev listimage
keymap kill less lessecho lesskey link listarea listattr listimage #listdev
listport listres listsem ln locate logger login logname ls lsindex m4 make
makebootable md5sum merge mimeset mkdos mkdir mkfifo mkfs mkindex modifiers mount
mount_nfs mountvolume mv nc netstat nl nohup od open passwd paste patch
@@ -145,7 +145,7 @@ AddFilesToHaikuImage beos system add-ons kernel bus_managers
AddFilesToHaikuImage beos system add-ons kernel busses agp_gart
: $(X86_ONLY)<agp_gart>intel ;
AddFilesToHaikuImage beos system add-ons kernel busses ide
: generic_ide_pci $(X86_ONLY)ide_isa silicon_image_3112 legacy_sata ;
: generic_ide_pci ; #$(X86_ONLY)ide_isa silicon_image_3112 legacy_sata ;
AddFilesToHaikuImage beos system add-ons kernel busses scsi
: ahci ;
AddFilesToHaikuImage beos system add-ons kernel busses usb
@@ -156,7 +156,7 @@ AddFilesToHaikuImage beos system add-ons kernel debugger
AddFilesToHaikuImage beos system add-ons kernel file_systems
: $(BEOS_ADD_ONS_FILE_SYSTEMS) ;
AddFilesToHaikuImage beos system add-ons kernel generic
: block_io dpc fast_log ide_adapter locked_pool mpu401 scsi_periph ;
: block_io dpc ide_adapter locked_pool mpu401 scsi_periph ;
AddFilesToHaikuImage beos system add-ons kernel partitioning_systems
: intel session ;
AddFilesToHaikuImage beos system add-ons kernel interrupt_controllers
@@ -172,7 +172,7 @@ AddDriversToHaikuImage : console dprintf $(X86_ONLY)keyboard null
AddDriversToHaikuImage audio hmulti : $(BEOS_ADD_ONS_DRIVERS_AUDIO) ;
AddDriversToHaikuImage midi : $(BEOS_ADD_ONS_DRIVERS_MIDI) ;
AddDriversToHaikuImage bus : usb_raw ; # fw_raw
AddDriversToHaikuImage disk scsi : scsi_cd scsi_dsk ;
AddDriversToHaikuImage disk scsi : scsi_dsk ; #scsi_cd;
AddDriversToHaikuImage disk usb : usb_disk ;
AddDriversToHaikuImage disk virtual : nbd ;
AddDriversToHaikuImage dvb : cx23882 ;
@@ -358,9 +358,9 @@ AddFilesToHaikuImage beos system : zbeos ;
AddBootModuleSymlinksToHaikuImage
pci $(X86_ONLY)isa config_manager ide scsi
$(PPC_ONLY)openpic
block_io fast_log ide_adapter locked_pool scsi_periph
ahci generic_ide_pci $(X86_ONLY)ide_isa silicon_image_3112 legacy_sata
scsi_cd scsi_dsk
block_io ide_adapter locked_pool scsi_periph
generic_ide_pci ahci # $(X86_ONLY)ide_isa silicon_image_3112 legacy_sata
scsi_dsk #scsi_cd
intel
bfs
;
@@ -553,7 +553,7 @@ AddGroupToHaikuImage users : 100 : ;
if $(HAIKU_IMAGE_HOST_NAME) {
actions BuildHaikuImageHostnameFile
{
echo "$(HAIKU_IMAGE_HOST_NAME)" > $(1)
echo "$(HAIKU_IMAGE_HOST_NAME)" > $(1)
}
local file = <haiku-image>hostname ;
+9 -7
View File
@@ -5,9 +5,7 @@
#ifndef __BLOCK_IO_H__
#define __BLOCK_IO_H__
/*
Part of Open block device manager
/*!
Block devices can be easily written by providing the interface
specified hereinafter. The block device manager takes care of
DMA and other restrictions imposed by underlying controller or
@@ -24,7 +22,6 @@ typedef struct block_io_device_info *block_io_device;
typedef struct block_io_handle_info *block_io_handle;
// cookies issued by device driver
typedef struct block_device_device_cookie *block_device_device_cookie;
typedef struct block_device_handle_cookie *block_device_handle_cookie;
@@ -59,15 +56,20 @@ typedef struct phys_vecs {
// maximum number of scatter/gather blocks (uint32, optional, default: unlimited)
#define B_BLOCK_DEVICE_MAX_SG_BLOCKS "block_device/max_sg_blocks"
typedef struct block_device_cookie {
struct device_node *node;
} block_device_cookie;
// interface to be provided by device driver
typedef struct block_device_interface {
driver_module_info info;
void (*set_device)(block_device_cookie *cookie, block_io_device device);
// iovecs are physical address here
// pos and num_blocks are in blocks; bytes_transferred in bytes
// vecs are guaranteed to describe enough data for given block count
status_t (*open)(block_device_device_cookie device, block_device_handle_cookie *handle);
status_t (*open)(block_device_cookie *cookie, block_device_handle_cookie *handle);
status_t (*close)(block_device_handle_cookie handle);
status_t (*free)(block_device_handle_cookie handle);
@@ -79,12 +81,12 @@ typedef struct block_device_interface {
status_t (*ioctl)(block_device_handle_cookie handle, int op, void *buf, size_t len);
} block_device_interface;
#define B_BLOCK_IO_MODULE_NAME "generic/block_io/v1"
#define B_BLOCK_IO_DEVICE_MODULE_NAME "generic/block_io/device_v1"
// Interface for Drivers
// blkman interface used for callbacks done by driver
// interface used for callbacks done by driver
typedef struct block_io_for_driver_interface {
module_info info;
+12 -18
View File
@@ -1,18 +1,11 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
/*
Part of Open IDE bus manager
IDE bus manager interface
*/
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef __IDE_H__
#define __IDE_H__
#include <bus_manager.h>
#include <device_manager.h>
#include <KernelExport.h>
@@ -37,22 +30,27 @@
union ide_task_file;
typedef unsigned int ide_reg_mask;
// channel cookie, issued by ide bus manager
typedef struct ide_bus_info *ide_channel;
// interface of controller driver
typedef struct {
driver_module_info info;
void (*set_channel)(void *cookie, ide_channel channel);
status_t (*write_command_block_regs)
(void *channel_cookie, union ide_task_file *tf, ide_reg_mask mask);
status_t (*read_command_block_regs)
(void *channel_cookie, union ide_task_file *tf, ide_reg_mask mask);
uint8 (*get_altstatus) (void *channel_cookie);
status_t (*write_device_control) (void *channel_cookie, uint8 val);
status_t (*write_device_control) (void *channel_cookie, uint8 val);
status_t (*write_pio) (void *channel_cookie, uint16 *data, int count, bool force_16bit );
status_t (*read_pio) (void *channel_cookie, uint16 *data, int count, bool force_16bit );
status_t (*prepare_dma)(void *channel_cookie,
status_t (*prepare_dma)(void *channel_cookie,
const physical_entry *sg_list, size_t sg_list_count,
bool write);
status_t (*start_dma)(void *channel_cookie);
@@ -60,10 +58,6 @@ typedef struct {
} ide_controller_interface;
// channel cookie, issued by ide bus manager
typedef struct ide_bus_info *ide_channel;
// Interface for Controller Driver
// interface of bus manager as seen from controller driver
@@ -77,7 +71,7 @@ typedef struct {
} ide_for_controller_interface;
#define IDE_FOR_CONTROLLER_MODULE_NAME "bus_managers/ide/controller/v1"
#define IDE_FOR_CONTROLLER_MODULE_NAME "bus_managers/ide/controller/driver_v1"
#endif /* __IDE_H__ */
+14 -14
View File
@@ -12,15 +12,15 @@
All ISA drivers must be Universal driver (see pnp_manager.h), as they
are all direct children of the ISA bus node. Having an ISA PnP bus manager
(which we don't), one node would be created per ISA device and thus you
could write Specific drivers, but under normal ISA we don't even know
(which we don't), one node would be created per ISA device and thus you
could write Specific drivers, but under normal ISA we don't even know
how many devices are there, therefore the Universal driver trick.
Apart from the loading, the main change is the resource manager. In
a driver, you must allocate the resources before registering the node and
deallocate it when your node is removed and if the driver isn't loaded at
this time. If it is, you must delay deallocation until the driver gets
unloaded to make sure no new driver touches the same resources like you
unloaded to make sure no new driver touches the same resources like you
meanwhile.
*/
@@ -30,22 +30,22 @@
#include <device_manager.h>
#include <ISA.h>
// maximum size of one dma transfer
// maximum size of one dma transfer
// (in bytes for 8 bit transfer, in words for 16 bit transfer)
#define B_MAX_ISA_DMA_COUNT 0x10000
typedef struct isa2_module_info {
bus_module_info info;
driver_module_info info;
uint8 (*read_io_8)(int mapped_io_addr);
void (*write_io_8)(int mapped_io_addr, uint8 value);
uint16 (*read_io_16)(int mapped_io_addr);
void (*write_io_16)(int mapped_io_addr, uint16 value);
uint32 (*read_io_32)(int mapped_io_addr);
void (*write_io_32)(int mapped_io_addr, uint32 value);
uint8 (*read_io_8)( int mapped_io_addr );
void (*write_io_8)( int mapped_io_addr, uint8 value );
uint16 (*read_io_16)( int mapped_io_addr );
void (*write_io_16)( int mapped_io_addr, uint16 value );
uint32 (*read_io_32)( int mapped_io_addr );
void (*write_io_32)( int mapped_io_addr, uint32 value );
// don't know what it's for, remains for compatibility
void *(*ram_address)( const void *physical_address_in_system_memory );
void *(*ram_address)(const void *physical_address_in_system_memory);
// start dma transfer (scattered DMA is not supported as it's EISA specific)
status_t (*start_isa_dma)(
@@ -64,4 +64,4 @@ typedef struct isa2_module_info {
#define ISA_DRIVERS_DIR "isa"
#endif
#endif /* _ISA2_H */
+26 -144
View File
@@ -1,164 +1,46 @@
/*
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Copyright 2008, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
PCI bus manager
*/
#ifndef _PCI2_H
#define _PCI2_H
#include <device_manager.h>
#include <PCI.h>
// currently, this structure is disabled to avoid collision with R5 header
#if 0
typedef struct pci_info {
ushort vendor_id; /* vendor id */
ushort device_id; /* device id */
uchar bus; /* bus number */
uchar device; /* device number on bus */
uchar function; /* function number in device */
uchar revision; /* revision id */
uchar class_api; /* specific register interface type */
uchar class_sub; /* specific device function */
uchar class_base; /* device type (display vs network, etc) */
uchar line_size; /* cache line size in 32 bit words */
uchar latency; /* latency timer */
uchar header_type; /* header type */
uchar bist; /* built-in self-test */
uchar reserved; /* filler, for alignment */
union {
struct {
ulong cardbus_cis; /* CardBus CIS pointer */
ushort subsystem_id; /* subsystem (add-in card) id */
ushort subsystem_vendor_id; /* subsystem (add-in card) vendor id */
ulong rom_base; /* rom base address, viewed from host */
ulong rom_base_pci; /* rom base addr, viewed from pci */
ulong rom_size; /* rom size */
ulong base_registers[6]; /* base registers, viewed from host */
ulong base_registers_pci[6]; /* base registers, viewed from pci */
ulong base_register_sizes[6]; /* size of what base regs point to */
uchar base_register_flags[6]; /* flags from base address fields */
uchar interrupt_line; /* interrupt line */
uchar interrupt_pin; /* interrupt pin */
uchar min_grant; /* burst period @ 33 Mhz */
uchar max_latency; /* how often PCI access needed */
} h0;
struct {
ulong base_registers[2]; /* base registers, viewed from host */
ulong base_registers_pci[2]; /* base registers, viewed from pci */
ulong base_register_sizes[2]; /* size of what base regs point to */
uchar base_register_flags[2]; /* flags from base address fields */
uchar primary_bus;
uchar secondary_bus;
uchar subordinate_bus;
uchar secondary_latency;
uchar io_base;
uchar io_limit;
ushort secondary_status;
ushort memory_base;
ushort memory_limit;
ushort prefetchable_memory_base;
ushort prefetchable_memory_limit;
ulong prefetchable_memory_base_upper32;
ulong prefetchable_memory_limit_upper32;
ushort io_base_upper16;
ushort io_limit_upper16;
ulong rom_base; /* rom base address, viewed from host */
ulong rom_base_pci; /* rom base addr, viewed from pci */
uchar interrupt_line; /* interrupt line */
uchar interrupt_pin; /* interrupt pin */
ushort bridge_control;
} h1;
} u;
} pci_info;
typedef struct pci_device pci_device;
#endif
typedef struct pci_device_info *pci_device;
// Interface to one PCI device.
// Actually, this is a _function_ of a device only, but
// pci_function_module_info would be a bit non-intuitive
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, addr_t mappedIOAddress);
void (*write_io_8)(pci_device *device, addr_t mappedIOAddress,
uint8 value);
uint16 (*read_io_16)(pci_device *device, addr_t mappedIOAddress);
void (*write_io_16)(pci_device *device, addr_t mappedIOAddress,
uint16 value);
uint32 (*read_io_32)(pci_device *device, addr_t mappedIOAddress);
void (*write_io_32)(pci_device *device, addr_t mappedIOAddress,
uint32 value);
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 offset, /* offset in configuration space */
uchar size, /* # bytes to write (1, 2 or 4) */
uint32 value); /* value to write */
void *(*ram_address)(pci_device *device, const void *physicalAddress);
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 );
status_t (*allocate_ioports)( uint16 ioport_base, size_t len, const char *name );
status_t (*release_ioports)( uint16 ioport_base, size_t len );*/
status_t (*get_pci_info)(pci_device device, struct pci_info *info);
status_t (*find_pci_capability)(pci_device device,
uchar cap_id,
uchar *offset);
uint32 (*read_pci_config)(pci_device *device, uint8 offset,
uint8 size);
void (*write_pci_config)(pci_device *device, uint8 offset,
uint8 size, uint32 value);
status_t (*find_pci_capability)(pci_device *device, uint8 capID,
uint8 *offset);
void (*get_pci_info)(pci_device *device, struct pci_info *info);
} pci_device_module_info;
// directory of PCI drivers
#define PCI_DRIVERS_DIR "pci"
/* Attributes of PCI device nodes */
#define B_PCI_DEVICE_DOMAIN "pci/domain" /* uint32 */
#define B_PCI_DEVICE_BUS "pci/bus" /* uint8 */
#define B_PCI_DEVICE_DEVICE "pci/device" /* uint8 */
#define B_PCI_DEVICE_FUNCTION "pci/function" /* uint8 */
// attributes of PCI device nodes
// bus idx (uint8)
#define PCI_DEVICE_BUS_ITEM "pci/bus"
// device idx (uint8)
#define PCI_DEVICE_DEVICE_ITEM "pci/device"
// function idx (uint8)
#define PCI_DEVICE_FUNCTION_ITEM "pci/function"
// vendor id (uint16)
#define PCI_DEVICE_VENDOR_ID_ITEM "pci/vendor_id"
// device id (uint16)
#define PCI_DEVICE_DEVICE_ID_ITEM "pci/device_id"
// subsystem id (uint16)
#define PCI_DEVICE_SUBSYSTEM_ID_ITEM "pci/subsystem_id"
// subvendor id (uint16)
#define PCI_DEVICE_SUBVENDOR_ID_ITEM "pci/subvendor_id"
// device base class (uint8)
#define PCI_DEVICE_BASE_CLASS_ID_ITEM "pci/class/base_id"
// device subclass (uint8)
#define PCI_DEVICE_SUB_CLASS_ID_ITEM "pci/class/sub_id"
// device api (uint8)
#define PCI_DEVICE_API_ID_ITEM "pci/class/api_id"
// dynamic consumer patterns for PCI devices
#define PCI_DEVICE_DYNAMIC_CONSUMER_0 \
PCI_DRIVERS_DIR "/" \
"vendor %" PCI_DEVICE_VENDOR_ID_ITEM "%|" \
", device %" PCI_DEVICE_DEVICE_ID_ITEM "%|" \
", subsystem %" PCI_DEVICE_SUBSYSTEM_ID_ITEM "%|" \
", subvendor %" PCI_DEVICE_SUBVENDOR_ID_ITEM "%"
#define PCI_DEVICE_DYNAMIC_CONSUMER_1 \
PCI_DRIVERS_DIR "/" \
"base_class %" PCI_DEVICE_BASE_CLASS_ID_ITEM "%|" \
", sub_class %" PCI_DEVICE_SUB_CLASS_ID_ITEM "%|" \
", api %" PCI_DEVICE_API_ID_ITEM "%"
#endif
#endif /* _PCI2_H */
+43 -42
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2007, Haiku, Inc. All RightsReserved.
* Copyright 2004-2008, Haiku, Inc. All RightsReserved.
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -11,13 +11,13 @@
SCSI bus manager interface
The bus manager interface is _based_ on CAM, but I've modified it because :-
- HBA engine, target mode and queue freezing (and probably other features)
- HBA engine, target mode and queue freezing (and probably other features)
aren't supported (at least the first two aren't supported by linux too ;)
- Asynchronous events aren't supported (no OS/driver I know uses them)
- P/T/L was defined by number not by handle, requiring many redundant tests
and thus making adding/removing of devices/busses very hard, especially if
PnP is to be supported
- single entry system as proposed by CAM involves extra tests and overhead
- single entry system as proposed by CAM involves extra tests and overhead
because of generalized data structure
@@ -26,16 +26,16 @@
Something about requests involving data transfer: you can either specify
the virtual address in <data> of CCB (in which case it must be continuous),
or store a pointer to a S/G list that contains physical addresses in
<sg_list>/<sg_count>. If <sg_list> is non-Null, <data> is ignored.
The S/G list must be in kernel space because the request can be executed
in a different thread context. This is also the reason why the S/G list has
<sg_list>/<sg_count>. If <sg_list> is non-Null, <data> is ignored.
The S/G list must be in kernel space because the request can be executed
in a different thread context. This is also the reason why the S/G list has
to contain physical addresses. For obvious reason, the data buffer specified
by <sg_list> must be locked, but <data> doesn't need to be.
You can either execute the request synchronously ("sync_io") or
asynchronously ("async_io"; you have to acquire <completion_sem> to find
out when the request is finished). In the first case you can use either
<data> or <sg_list>, in the latter <sg_list> only.
You can either execute the request synchronously ("sync_io") or
asynchronously ("async_io"; you have to acquire <completion_sem> to find
out when the request is finished). In the first case you can use either
<data> or <sg_list>, in the latter <sg_list> only.
The SCSI bus manager takes care that the controller can access the data
via DMA by copying it into a buffer if necessary. For the paging path,
@@ -49,28 +49,28 @@
<data> is a safe bet.
For SIM writers:
For SIM writers:
Requests sent by peripheral drivers are forwarded to the <scsi_io> entry
of the SIM. You should return as soon as some waiting is required.
of the SIM. You should return as soon as some waiting is required.
Usually, the controller raises an IRQ when a request can be continued
or is finished. As interrupt handlers must be as fast as possible, you
can schedule a DPC in the handler (<schedule_dpc>) which executed by a
high priority service thread that is spawned by the SCSI bus manager
for each bus. This service thread also takes care to submit waiting
can schedule a DPC in the handler (<schedule_dpc>) which executed by a
high priority service thread that is spawned by the SCSI bus manager
for each bus. This service thread also takes care to submit waiting
requests.
You can specify a maximum number of concurrent requests per bus via
path_inquiry (<hba_queue_size>) for the bus. The device limit is
path_inquiry (<hba_queue_size>) for the bus. The device limit is
determined via INQUIRY. If you need a lower/dynamic limit, you can refuse
a request by <requeue>. If <bus_overflow> is true, no further requests
to the bus will be sent, if <bus_overflow> is false, no further requests
to the device will be sent. To terminate the overflow condition, call
<cont_send_device>/<cont_send_bus>. It also terminated when a request
for the bus/device is finished via <finished> or <resubmit>.
Because of the asynchronous nature, requests may still arrive after the
overflow condition being signalled, so you should add a safety test to
<scsi_io>.
Because of the asynchronous nature, requests may still arrive after the
overflow condition being signalled, so you should add a safety test to
<scsi_io>.
If a problem occurs during execution, you can ask for a restart via
<resubmit>. The request in question will be submitted as soon as possible.
@@ -86,8 +86,8 @@
READ6/WRITE6 commands to READ10/WRITE10 commands, MODE REQUEST6/SENSE6
to MODE REQUEST10/SENSE10 and fix the version fields of INQUIRY results,
so ATAPI devices can be used like standard SCSI devices. Further, the
SCSI bus manager can emulate auto-sense by executing a REQUEST SENSE
if <subsys_status> is SCSI_REQ_CMP_ERR and <device_status> is
SCSI bus manager can emulate auto-sense by executing a REQUEST SENSE
if <subsys_status> is SCSI_REQ_CMP_ERR and <device_status> is
SCSI_STATUS_CHECK_CONDITION when a request is finished. This emulation
may be enhanced/generalized in the future.
*/
@@ -296,7 +296,7 @@ typedef struct scsi_device_interface {
driver_module_info info;
// get CCB
// warning: if pool of CCBs is exhausted, this call is delayed until a
// warning: if pool of CCBs is exhausted, this call is delayed until a
// CCB is freed, so don't try to allocate more then one CCB at once!
scsi_ccb *(*alloc_ccb)(scsi_device device);
// free CCB
@@ -320,7 +320,7 @@ typedef struct scsi_device_interface {
status_t (*ioctl)(scsi_device device, uint32 op, void *buffer, size_t length);
} scsi_device_interface;
#define SCSI_DEVICE_MODULE_NAME "bus_managers/scsi/driver/v1"
#define SCSI_DEVICE_MODULE_NAME "bus_managers/scsi/device/driver_v1"
// Bus node
@@ -333,10 +333,10 @@ typedef struct scsi_device_interface {
#define SCSI_BUS_TYPE_NAME "scsi/bus"
// SCSI bus node driver.
// This interface can be used by peripheral drivers to access the
// This interface can be used by peripheral drivers to access the
// bus directly.
typedef struct scsi_bus_interface {
bus_module_info info;
driver_module_info info;
// get information about host controller
uchar (*path_inquiry)(scsi_bus bus, scsi_path_inquiry *inquiry_data);
@@ -345,7 +345,7 @@ typedef struct scsi_bus_interface {
} scsi_bus_interface;
// name of SCSI bus node driver
#define SCSI_BUS_MODULE_NAME "bus_managers/scsi/bus/v1"
#define SCSI_BUS_MODULE_NAME "bus_managers/scsi/bus/driver_v1"
// Interface for SIM
@@ -354,7 +354,7 @@ typedef struct scsi_bus_interface {
typedef struct scsi_dpc_info *scsi_dpc_cookie;
// Bus manager interface used by SCSI controller drivers.
// SCSI controller drivers get this interface passed via their init_device
// SCSI controller drivers get this interface passed via their init_device
// method. Further, they must specify this driver as their fixed consumer.
typedef struct scsi_for_sim_interface {
driver_module_info info;
@@ -363,7 +363,7 @@ typedef struct scsi_for_sim_interface {
// bus_overflow: true - too many bus requests
// false - too many device requests
// bus/device won't receive requests until cont_sent_bus/cont_send_device
// is called or a request is finished via finished();
// is called or a request is finished via finished();
// to avoid race conditions (reporting a full and a available bus at once)
// the SIM should synchronize calls to requeue, resubmit and finished
void (*requeue)(scsi_ccb *ccb, bool bus_overflow);
@@ -374,7 +374,7 @@ typedef struct scsi_for_sim_interface {
// num_requests: number of requests that were handled by device
// when the request was sent (read: how full was the device
// queue); needed to find out how large the device queue is;
// e.g. if three were already running plus this request makes
// e.g. if three were already running plus this request makes
// num_requests=4
void (*finished)(scsi_ccb *ccb, uint num_requests);
@@ -404,7 +404,7 @@ typedef struct scsi_for_sim_interface {
} scsi_for_sim_interface;
#define SCSI_FOR_SIM_MODULE_NAME "bus_managers/scsi/sim/v1"
#define SCSI_FOR_SIM_MODULE_NAME "bus_managers/scsi/sim/driver_v1"
// SIM Node
@@ -416,34 +416,35 @@ typedef struct scsi_for_sim_interface {
// controller name (required, string)
#define SCSI_DESCRIPTION_CONTROLLER_NAME "controller_name"
typedef void * scsi_sim_cookie;
typedef void *scsi_sim_cookie;
// SIM interface
// SCSI controller drivers must provide this interface
typedef struct scsi_sim_interface {
driver_module_info info;
void (*set_scsi_bus)(scsi_sim_cookie cookie, scsi_bus bus);
// execute request
void (*scsi_io)( scsi_sim_cookie cookie, scsi_ccb *ccb );
void (*scsi_io)(scsi_sim_cookie cookie, scsi_ccb *ccb);
// abort request
uchar (*abort)( scsi_sim_cookie cookie, scsi_ccb *ccb_to_abort );
uchar (*abort)(scsi_sim_cookie cookie, scsi_ccb *ccb_to_abort);
// reset device
uchar (*reset_device)( scsi_sim_cookie cookie, uchar target_id, uchar target_lun );
uchar (*reset_device)(scsi_sim_cookie cookie, uchar target_id, uchar target_lun);
// terminate request
uchar (*term_io)( scsi_sim_cookie cookie, scsi_ccb *ccb_to_terminate );
uchar (*term_io)(scsi_sim_cookie cookie, scsi_ccb *ccb_to_terminate);
// get information about bus
uchar (*path_inquiry)( scsi_sim_cookie cookie, scsi_path_inquiry *inquiry_data );
uchar (*path_inquiry)(scsi_sim_cookie cookie, scsi_path_inquiry *inquiry_data);
// scan bus
// this is called immediately before the SCSI bus manager scans the bus
uchar (*scan_bus)( scsi_sim_cookie cookie );
uchar (*scan_bus)(scsi_sim_cookie cookie);
// reset bus
uchar (*reset_bus)( scsi_sim_cookie cookie );
// get restrictions of one device
uchar (*reset_bus)(scsi_sim_cookie cookie);
// get restrictions of one device
// (used for non-SCSI transport protocols and bug fixes)
void (*get_restrictions)(
scsi_sim_cookie cookie,
void (*get_restrictions)(scsi_sim_cookie cookie,
uchar target_id, // target id
bool *is_atapi, // set to true if this is an ATAPI device that
// needs some commands emulated
+103 -122
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2005, Haiku Inc. All Rights Reserved.
* Copyright 2004-2008, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT license.
*/
#ifndef _DEVICE_MANAGER_H
@@ -11,189 +11,170 @@
#include <module.h>
// type of I/O resource
/* type of I/O resource */
enum {
IO_MEM = 1,
IO_PORT = 2,
ISA_DMA_CHANNEL = 3
B_IO_MEMORY = 1,
B_IO_PORT = 2,
B_ISA_DMA_CHANNEL = 3
};
// I/O resource description
/* I/O resource description */
typedef struct {
uint32 type;
// type of I/O resource
/* type of I/O resource */
uint32 base;
// I/O memory: first physical address (32 bit)
// I/O port: first port address (16 bit)
// ISA DMA channel: channel number (0-7)
/* I/O memory: first physical address (32 bit)
* I/O port: first port address (16 bit)
* ISA DMA channel: channel number (0-7)
*/
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
/* I/O memory: size of address range (32 bit)
* I/O port: size of port range (16 bit)
* ISA DMA channel: must be 1
*/
} io_resource;
// attribute of a device node
/* attribute of a device node */
typedef struct {
const char *name;
type_code type; // for supported types, see value
type_code type; /* for supported types, see value */
union {
uint8 ui8; // B_UINT8_TYPE
uint16 ui16; // B_UINT16_TYPE
uint32 ui32; // B_UINT32_TYPE
uint64 ui64; // B_UINT64_TYPE
const char *string; // B_STRING_TYPE
struct { // B_RAW_TYPE
void *data;
uint8 ui8; /* B_UINT8_TYPE */
uint16 ui16; /* B_UINT16_TYPE */
uint32 ui32; /* B_UINT32_TYPE */
uint64 ui64; /* B_UINT64_TYPE */
const char *string; /* B_STRING_TYPE */
struct { /* B_RAW_TYPE */
const void *data;
size_t length;
} raw;
} value;
} device_attr;
typedef struct device_node_info *device_node_handle;
typedef struct io_resource_info *io_resource_handle;
typedef struct device_attr_info *device_attr_handle;
typedef struct device_node device_node;
typedef struct driver_module_info driver_module_info;
// interface of the device manager
/* interface of the device manager */
typedef struct device_manager_info {
module_info info;
status_t (*init_driver)(device_node_handle node, void *userCookie,
driver_module_info **interface, void **cookie);
status_t (*uninit_driver)(device_node_handle node);
status_t (*rescan_node)(device_node *node);
status_t (*rescan)(device_node_handle node);
status_t (*register_node)(device_node *parent, const char *moduleName,
const device_attr *attrs, const io_resource *ioResources,
device_node **_node);
status_t (*unregister_node)(device_node *node);
status_t (*register_device)(device_node_handle parent,
const device_attr *attrs,
const io_resource_handle *io_resources,
device_node_handle *node);
status_t (*unregister_device)(device_node_handle node);
status_t (*get_driver)(device_node *node, driver_module_info **_module,
void **_cookie);
device_node_handle (*get_root)();
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);
device_node *(*get_root_node)();
status_t (*get_next_child_node)(device_node *parent,
const device_attr *attrs, device_node **node);
device_node *(*get_parent_node)(device_node *node);
void (*put_node)(device_node *node);
status_t (*acquire_io_resources)(io_resource *resources,
io_resource_handle *handles);
status_t (*release_io_resources)(const io_resource_handle *handles);
status_t (*publish_device)(device_node *node, const char *path,
const char *deviceModuleName);
status_t (*unpublish_device)(device_node *node, const char *path);
int32 (*create_id)(const char *generator);
status_t (*free_id)(const char *generator, uint32 id);
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,
const char *name, uint16 *value, bool recursive);
status_t (*get_attr_uint32)(device_node_handle node,
const char *name, uint32 *value, bool recursive);
status_t (*get_attr_uint64)(device_node_handle node,
const char *name, uint64 *value, bool recursive);
status_t (*get_attr_string)(device_node_handle node,
const char *name, char **value, bool recursive);
status_t (*get_attr_raw)(device_node_handle node,
const char *name, void **data, size_t *_size,
bool recursive);
status_t (*get_attr_uint8)(const device_node *node, const char *name,
uint8 *value, bool recursive);
status_t (*get_attr_uint16)(const device_node *node, const char *name,
uint16 *value, bool recursive);
status_t (*get_attr_uint32)(const device_node *node, const char *name,
uint32 *value, bool recursive);
status_t (*get_attr_uint64)(const device_node *node, const char *name,
uint64 *value, bool recursive);
status_t (*get_attr_string)(const device_node *node, const char *name,
const char **_value, bool recursive);
status_t (*get_attr_raw)(const device_node *node, const char *name,
const void **_data, size_t *_size, bool recursive);
status_t (*get_next_attr)(device_node_handle node,
device_attr_handle *attrHandle);
status_t (*release_attr)(device_node_handle node,
device_attr_handle attr_handle);
status_t (*retrieve_attr)(device_attr_handle attr_handle,
const device_attr **attr);
status_t (*write_attr)(device_node_handle node,
const device_attr *attr);
status_t (*remove_attr)(device_node_handle node, const char *name);
status_t (*get_next_attr)(device_node *node, device_attr **_attr);
} device_manager_info;
#define B_DEVICE_MANAGER_MODULE_NAME "system/device_manager/v1"
// interface of device driver
/* interface of device driver */
struct driver_module_info {
module_info info;
float (*supports_device)(device_node_handle parent, bool *_noConnection);
status_t (*register_device)(device_node_handle parent);
float (*supports_device)(device_node *parent);
status_t (*register_device)(device_node *parent);
status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie);
status_t (*uninit_driver)(void *cookie);
status_t (*init_driver)(device_node *node, void **_driverCookie);
void (*uninit_driver)(void *driverCookie);
status_t (*register_child_devices)(void *driverCookie);
status_t (*rescan_child_devices)(void *driverCookie);
void (*device_removed)(device_node_handle node, void *cookie);
void (*device_cleanup)(device_node_handle node);
void (*get_supported_paths)(const char ***_busses, const char ***_devices);
void (*device_removed)(void *driverCookie);
status_t (*suspend)(void *driverCookie, int32 state);
status_t (*resume)(void *driverCookie);
};
// standard device node attributes
/* standard device node attributes */
#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_DEVICE_PRETTY_NAME "device/pretty name" /* string */
#define B_DEVICE_MAPPING "device/mapping" /* string */
#define B_DEVICE_BUS "device/bus" /* string */
#define B_DEVICE_FIXED_CHILD "device/fixed child" /* string */
#define B_DEVICE_FLAGS "device/flags" /* uint32 */
#define B_DRIVER_UNIQUE_DEVICE_ID "unique id"
#define B_DRIVER_DEVICE_TYPE "device type"
#define B_DEVICE_VENDOR_ID "device/vendor" /* uint16 */
#define B_DEVICE_ID "device/id" /* uint16 */
#define B_DEVICE_TYPE "device/type"
/* uint16, PCI base class */
#define B_DEVICE_SUB_TYPE "device/subtype"
/* uint16, PCI sub type */
#define B_DEVICE_INTERFACE "device/interface"
/* uint16, PCI class API */
#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"
#define B_INTERRUPT_CONTROLLER_DRIVER_TYPE "interrupt controller"
#define B_DEVICE_UNIQUE_ID "device/unique id" /* string */
#define PNP_DRIVER_CONNECTION "connection"
// connection of parent the device is attached to (optional, string)
// there can be only one device per connection
/* device flags */
#define B_FIND_CHILD_ON_DEMAND 0x01
#define B_FIND_MULTIPLE_CHILDREN 0x02
#define B_KEEP_DRIVER_LOADED 0x04
// interface of a bus device driver
/* interface of device */
typedef struct bus_module_info {
driver_module_info info;
typedef struct io_request io_request;
// scan the bus and register all devices.
status_t (*register_child_devices)(void *cookie);
struct device_module_info {
module_info info;
// 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_bus)(void *cookie);
} bus_module_info;
status_t (*init_device)(void *driverCookie, void **_deviceCookie);
void (*uninit_device)(void *deviceCookie);
void (*device_removed)(void *deviceCookie);
status_t (*open)(void *deviceCookie, const char *path, int openMode,
void **_cookie);
status_t (*close)(void *cookie);
status_t (*free)(void *cookie);
status_t (*read)(void *cookie, off_t pos, void *buffer, size_t *_length);
status_t (*write)(void *cookie, off_t pos, const void *buffer,
size_t *_length);
status_t (*io)(void *cookie, io_request *request);
status_t (*control)(void *cookie, uint32 op, void *buffer, size_t length);
status_t (*select)(void *cookie, uint8 event, selectsync *sync);
status_t (*deselect)(void *cookie, uint8 event, selectsync *sync);
};
// 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"
extern struct device_manager_info *gDeviceManager;
#endif /* _DEVICE_MANAGER_H */
-80
View File
@@ -1,80 +0,0 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
/*
Fast logging facilities.
This logging is much faster then dprintf and is saver
against buffer overflow conditions.
Clients have to define events by creating an array of
fast_log_type entries, each consisting of a code and the
associated human-readable description. During logging,
only the code is stored to save space and time. Also,
all arguments are stored binary (currently, they must
be of type uint32). Conversion to human-readable text is
post-poned until the logging data is read or a client
connection is closed (as this invalidates the event-
description binding).
The reader interface is /dev/FAST_LOG_DEVFS_NAME. This
device can only be read from (no seeking or further
functionality) and does not block if there is no data.
This is because if you want to store the log into a
file, the file access may lead to further logging data,
so doing a sleep between reads saves logging entries.
*/
#ifndef FAST_LOG_H
#define FAST_LOG_H
#include <module.h>
// one event type as defined by client
typedef struct fast_log_event_type {
// code of event (zero means end-of-list)
int16 event;
// human-readable description
const char *description;
} fast_log_event_type;
// handle of client connection
typedef struct fast_log_connection *fast_log_handle;
// client interface
typedef struct fast_log_info {
module_info minfo;
// open client connection
// prefix - prefix to print in log before each event
// types - array of event types; last entry must have event=0
fast_log_handle (*start_log)(const char *prefix, fast_log_event_type types[]);
// close client connection
void (*stop_log)(fast_log_handle handle);
// log an entry without arguments
void (*log_0)(fast_log_handle handle, int event);
// log an entry with one argument
void (*log_1)(fast_log_handle handle, int event, uint32 param1);
// log an entry with two arguments
void (*log_2)(fast_log_handle handle, int event, uint32 param1, uint32 param2);
// log an entry with three arguments
void (*log_3)(fast_log_handle handle, int event, uint32 param1, uint32 param2, uint32 param3);
// log an entry with four arguments
void (*log_4)(fast_log_handle handle, int event, uint32 param1, uint32 param2, uint32 param3, uint32 param4);
// log an entry with n arguments
// don't cheat on num_params!
void (*log_n)(fast_log_handle handle, int event, int num_params, ...);
} fast_log_info;
// name of client interface module
#define FAST_LOG_MODULE_NAME "generic/fast_log/v1"
// name of device to read logging data from
#define FAST_LOG_DEVFS_NAME "fast_log"
#endif
+37 -34
View File
@@ -24,7 +24,7 @@
// one Physical Region Descriptor (PRD)
// (one region must not cross 64K boundary;
// (one region must not cross 64K boundary;
// the PRD table must not cross a 64K boundary)
typedef struct prd_entry {
uint32 address; // physical address of block (must be even)
@@ -91,21 +91,21 @@ enum {
// info about one channel
typedef struct ide_adapter_channel_info {
pci_device_module_info *pci;
pci_device device;
pci_device *device;
uint16 command_block_base; // io address command block
uint16 control_block_base; // io address control block
uint16 bus_master_base;
int intnum; // interrupt number
int intnum; // interrupt number
uint32 lost; // != 0 if device got removed, i.e. if it must not
// be accessed anymore
ide_channel ide_channel;
device_node_handle node;
device_node *node;
int32 (*inthand)( void *arg );
area_id prd_area;
prd_entry *prdt;
uint32 prdt_phys;
@@ -116,14 +116,14 @@ typedef struct ide_adapter_channel_info {
// info about controller
typedef struct ide_adapter_controller_info {
pci_device_module_info *pci;
pci_device device;
pci_device *device;
uint16 bus_master_base;
uint32 lost; // != 0 if device got removed, i.e. if it must not
// be accessed anymore
device_node_handle node;
device_node *node;
} ide_adapter_controller_info;
@@ -131,6 +131,9 @@ typedef struct ide_adapter_controller_info {
typedef struct {
module_info info;
void (*set_channel)(ide_adapter_channel_info *channel,
ide_channel ideChannel);
// function calls that can be forwarded from actual driver
status_t (*write_command_block_regs)(ide_adapter_channel_info *channel,
ide_task_file *tf, ide_reg_mask mask);
@@ -138,7 +141,7 @@ typedef struct {
ide_task_file *tf, ide_reg_mask mask);
uint8 (*get_altstatus) (ide_adapter_channel_info *channel);
status_t (*write_device_control) (ide_adapter_channel_info *channel, uint8 val);
status_t (*write_device_control) (ide_adapter_channel_info *channel, uint8 val);
status_t (*write_pio)(ide_adapter_channel_info *channel, uint16 *data, int count, bool force_16bit);
status_t (*read_pio)(ide_adapter_channel_info *channel, uint16 *data, int count, bool force_16bit);
@@ -153,47 +156,47 @@ typedef struct {
int32 (*inthand)(void *arg);
// functions that must be called by init/uninit etc. of channel driver
status_t (*init_channel)(device_node_handle node, ide_channel ide_channel,
status_t (*init_channel)(device_node *node,
ide_adapter_channel_info **cookie, size_t total_data_size,
int32 (*inthand)(void *arg));
status_t (*uninit_channel)(ide_adapter_channel_info *channel);
void (*channel_removed)(device_node_handle node, ide_adapter_channel_info *channel);
void (*uninit_channel)(ide_adapter_channel_info *channel);
void (*channel_removed)(ide_adapter_channel_info *channel);
// publish channel node
status_t (*publish_channel)(device_node_handle controller_node,
status_t (*publish_channel)(device_node *controller_node,
const char *channel_module_name, uint16 command_block_base,
uint16 control_block_base, uint8 intnum, bool can_dma,
uint8 channel_index, const char *name,
io_resource_handle *resources, device_node_handle *node);
uint8 channel_index, const char *name,
const io_resource *resources, device_node **node);
// verify channel configuration and publish node on success
status_t (*detect_channel)(pci_device_module_info *pci, pci_device pci_device,
device_node_handle controller_node, const char *channel_module_name,
status_t (*detect_channel)(pci_device_module_info *pci, pci_device *pciDevice,
device_node *controller_node, const char *channel_module_name,
bool controller_can_dma, uint16 command_block_base,
uint16 control_block_base, uint16 bus_master_base,
uint8 intnum, uint8 channel_index, const char *name,
device_node_handle *node, bool supports_compatibility_mode);
device_node **node, bool supports_compatibility_mode);
// functions that must be called by init/uninit etc. of controller driver
status_t (*init_controller)(device_node_handle node, void *user_cookie,
status_t (*init_controller)(device_node *node,
ide_adapter_controller_info **cookie, size_t total_data_size);
status_t (*uninit_controller)(ide_adapter_controller_info *controller);
void (*controller_removed)(device_node_handle node, ide_adapter_controller_info *controller);
void (*uninit_controller)(ide_adapter_controller_info *controller);
void (*controller_removed)(ide_adapter_controller_info *controller);
// publish controller node
status_t (*publish_controller)(device_node_handle parent, uint16 bus_master_base,
io_resource_handle *resources, const char *controller_driver,
status_t (*publish_controller)(device_node *parent, uint16 bus_master_base,
io_resource *resources, const char *controller_driver,
const char *controller_driver_type, const char *controller_name,
bool can_dma, bool can_cq, uint32 dma_alignment, uint32 dma_boundary,
uint32 max_sg_block_size, device_node_handle *node);
uint32 max_sg_block_size, device_node **node);
// verify controller configuration and publish node on success
status_t (*detect_controller)(pci_device_module_info *pci, pci_device pci_device,
device_node_handle parent, uint16 bus_master_base,
status_t (*detect_controller)(pci_device_module_info *pci, pci_device *pciDevice,
device_node *parent, uint16 bus_master_base,
const char *controller_driver, const char *controller_driver_type,
const char *controller_name, bool can_dma, bool can_cq,
uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
device_node_handle *node);
device_node **node);
// standard master probe for controller that registers controller and channel nodes
status_t (*probe_controller)(device_node_handle parent, const char *controller_driver,
status_t (*probe_controller)(device_node *parent, const char *controller_driver,
const char *controller_driver_type, const char *controller_name,
const char *channel_module_name, bool can_dma, bool can_cq,
uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
+25 -25
View File
@@ -8,13 +8,13 @@
#define _SCSI_PERIPH_H
/*
Use this module to minimize work required to write a SCSI
Use this module to minimize work required to write a SCSI
peripheral driver.
It takes care of:
- error handling
- medium changes (including restarting the medium)
- detection of medium capacity
- detection of medium capacity
*/
@@ -72,12 +72,12 @@ typedef struct scsi_periph_callbacks {
// (set to NULL if not a block device)
void (*set_capacity)( periph_device_cookie periph_device, uint64 capacity,
uint32 block_size );
// *** removable devices
// called when media got changed (can be NULL if medium is not changable)
// (you don't need to call periph->media_changed, but it's doesn't if you do)
// ccb - request at your disposal
void (*media_changed)( periph_device_cookie periph_device,
void (*media_changed)( periph_device_cookie periph_device,
scsi_ccb *request );
} scsi_periph_callbacks;
@@ -87,44 +87,44 @@ typedef struct scsi_periph_interface {
module_info info;
// *** init/cleanup ***
status_t (*register_device)(
status_t (*register_device)(
periph_device_cookie periph_device,
scsi_periph_callbacks *callbacks,
scsi_device scsi_device,
scsi_device scsi_device,
scsi_device_interface *scsi,
device_node_handle node,
device_node *node,
bool removable,
scsi_periph_device *driver );
status_t (*unregister_device)( scsi_periph_device driver );
// *** basic command execution ***
// exec command, retrying on problems
status_t (*safe_exec)(
scsi_periph_device periph_device,
scsi_ccb *request );
// exec simple command
status_t (*simple_exec)( scsi_periph_device device,
void *cdb, uchar cdb_len, void *data, size_t data_len,
status_t (*simple_exec)( scsi_periph_device device,
void *cdb, uchar cdb_len, void *data, size_t data_len,
int ccb_flags );
// *** file handling ***
// *** file handling ***
// to be called when a new file is opened
status_t (*handle_open)( scsi_periph_device device,
status_t (*handle_open)( scsi_periph_device device,
periph_handle_cookie periph_handle, scsi_periph_handle *res_handle );
// to be called when a file is closed
status_t (*handle_close)( scsi_periph_handle handle );
// to be called when a file is freed
status_t (*handle_free)( scsi_periph_handle handle );
// *** default implementation for block devices ***
// block read
// *** default implementation for block devices ***
// block read
// preferred_ccb_size - preferred command size; if zero, the shortest is used
status_t (*read)( scsi_periph_handle handle, const phys_vecs *vecs,
status_t (*read)( scsi_periph_handle handle, const phys_vecs *vecs,
off_t pos, size_t num_blocks, uint32 block_size, size_t *bytes_transferred,
int preferred_ccb_size );
// block write
// block write
// (see block_read)
status_t (*write)( scsi_periph_handle handle, const phys_vecs *vecs,
status_t (*write)( scsi_periph_handle handle, const phys_vecs *vecs,
off_t pos, size_t num_blocks, uint32 block_size, size_t *bytes_transferred,
int preferred_ccb_size );
// block ioctls
@@ -139,24 +139,24 @@ typedef struct scsi_periph_interface {
// convert result of *request to err_res
err_res (*check_error)( scsi_periph_device device, scsi_ccb *request );
// send start or stop command to device
// with_LoEj = true - include loading/ejecting,
// with_LoEj = true - include loading/ejecting,
// false - only do allow/deny
err_res (*send_start_stop)( scsi_periph_device device, scsi_ccb *request,
err_res (*send_start_stop)( scsi_periph_device device, scsi_ccb *request,
bool start, bool with_LoEj );
// checks media status and waits for device to become ready
// returns: B_OK, B_DEV_MEDIA_CHANGE_REQUESTED, B_NO_MEMORY or
// returns: B_OK, B_DEV_MEDIA_CHANGE_REQUESTED, B_NO_MEMORY or
// pending error reported by handle_get_error
status_t (*get_media_status)( scsi_periph_handle handle );
// compose device name consisting of prefix and path/target/LUN
// (result must be freed by caller)
char *(*compose_device_name)(device_node_handle device_node, const char *prefix);
char *(*compose_device_name)(device_node *device_node, const char *prefix);
// fill data with icon (for B_GET_ICON ioctl)
status_t (*get_icon)( icon_type type, device_icon *data );
// synchronizes (flush) the device cache
err_res(*synchronize_cache)(scsi_periph_device device, scsi_ccb *request);
err_res(*synchronize_cache)(scsi_periph_device device, scsi_ccb *request);
} scsi_periph_interface;
#define SCSI_PERIPH_MODULE_NAME "generic/scsi_periph/v1"
-9
View File
@@ -11,20 +11,11 @@
#include <Drivers.h>
struct kernel_args;
#ifdef __cplusplus
extern "C" {
#endif
void devfs_add_preloaded_drivers(struct kernel_args* args);
status_t devfs_add_driver(const char *path);
void devfs_driver_added(const char *path);
void devfs_driver_removed(const char *path);
status_t devfs_unpublish_file_device(const char *path);
status_t devfs_publish_file_device(const char *path, const char *filePath);
+7 -64
View File
@@ -1,85 +1,28 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected]. All rights reserved.
* Copyright 2004-2008, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_DEVICE_MANAGER_H
#define _KERNEL_DEVICE_MANAGER_H
#include <SupportDefs.h>
#include <device_manager.h>
#include <util/list.h>
typedef struct device_node_info device_node_info;
// info about a device node
struct device_node_info {
struct list_link siblings;
device_node_info *parent;
struct list children;
int32 ref_count;
driver_module_info *driver;
void *cookie;
bool registered; // true, if device is officially existent
bool blocked_by_rescan; // true, if device is blocked because of 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
int32 num_blocked_loads; // number of waiting load calls
sem_id load_block_sem; // sem for waiting load calls
int32 load_count; // # of finished load_driver() calls
int32 loading; // # of active (un)load_driver() calls
uint32 rescan_depth; // > 0 if scanning is active
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)
bool automatically_loaded; // loaded automatically because PNP_DRIVER_ALWAYS_LOADED
uint32 internal_id; // internal identifier
};
struct kernel_args;
#ifdef __cplusplus
extern "C" {
#endif
extern status_t probe_for_device_type(const char *type);
extern status_t device_manager_init(struct kernel_args *args);
extern status_t device_manager_init_post_modules(struct kernel_args *args);
void legacy_driver_add_preloaded(struct kernel_args *args);
// temporary/optional device manager syscall API
#define DEVICE_MANAGER_SYSCALLS "device_manager"
#define DM_GET_ROOT 1
#define DM_GET_CHILD 2
#define DM_GET_NEXT_CHILD 3
#define DM_GET_NEXT_ATTRIBUTE 4
struct dev_attr {
uint32 node_cookie;
uint32 cookie;
char name[255];
type_code type;
union {
uint8 ui8;
uint16 ui16;
uint32 ui32;
uint64 ui64;
char string[255];
struct {
void *data;
size_t length;
} raw;
} value;
};
status_t device_manager_probe(const char *path, uint32 updateCycle);
status_t device_manager_init(struct kernel_args *args);
status_t device_manager_init_post_modules(struct kernel_args *args);
#ifdef __cplusplus
}
#endif
#endif /* _KRENEL_DEVICE_MANAGER_H */
#endif /* _KERNEL_DEVICE_MANAGER_H */
@@ -0,0 +1,38 @@
/*
* Copyright 2004-2008, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYSTEM_DEVICE_MANAGER_DEFS_H
#define _SYSTEM_DEVICE_MANAGER_DEFS_H
#include <device_manager.h>
// temporary/optional device manager syscall API
#define DEVICE_MANAGER_SYSCALLS "device_manager"
#define DM_GET_ROOT 1
#define DM_GET_CHILD 2
#define DM_GET_NEXT_CHILD 3
#define DM_GET_NEXT_ATTRIBUTE 4
struct device_attr_info {
uint32 node_cookie;
uint32 cookie;
char name[255];
type_code type;
union {
uint8 ui8;
uint16 ui16;
uint32 ui32;
uint64 ui64;
char string[255];
struct {
void *data;
size_t length;
} raw;
} value;
};
#endif /* _SYSTEM_DEVICE_MANAGER_DEFS_H */
@@ -53,7 +53,7 @@ wait_for_drdy(ide_device_info *device)
}
/** reset entire IDE bus
/** reset entire IDE bus
* all active request apart from <ignore> are resubmitted
*/
@@ -66,8 +66,6 @@ reset_bus(ide_device_info *device, ide_qrequest *ignore)
dprintf("ide: reset_bus() device %p, bus %p\n", device, bus);
FAST_LOG0(bus->log, ev_ide_reset_bus);
if (device->reconnect_timer_installed) {
cancel_timer(&device->reconnect_timer.te);
device->reconnect_timer_installed = false;
@@ -82,7 +80,7 @@ reset_bus(ide_device_info *device, ide_qrequest *ignore)
// also, deactivate IRQ
// (as usual, we will get an IRQ on disabling, but as we leave them
// disabled for 2 ms, this false report is ignored)
if (controller->write_device_control(channel,
if (controller->write_device_control(channel,
ide_devctrl_nien | ide_devctrl_srst | ide_devctrl_bit3) != B_OK)
goto err0;
@@ -142,7 +140,6 @@ reset_device(ide_device_info *device, ide_qrequest *ignore)
dprintf("ide: reset_device() device %p\n", device);
FAST_LOG1(bus->log, ev_ide_reset_device, device->is_device1);
SHOW_FLOW0(3, "");
if (!device->is_atapi)
@@ -154,8 +151,8 @@ reset_device(ide_device_info *device, ide_qrequest *ignore)
}
// select device
if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf,
ide_mask_device_head) != B_OK)
if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf,
ide_mask_device_head) != B_OK)
goto err;
// safe original command to let caller restart it
@@ -171,12 +168,12 @@ reset_device(ide_device_info *device, ide_qrequest *ignore)
if (res != B_OK)
goto err;
// don't know how long to wait, but 31 seconds, like soft reset,
// don't know how long to wait, but 31 seconds, like soft reset,
// should be enough
if (!ide_wait(device, 0, ide_status_bsy, true, 31000000))
goto err;
// alright, resubmit all requests
// alright, resubmit all requests
finish_all_requests(device, ignore, SCSI_SCSI_BUS_RESET, true);
SHOW_FLOW0(3, "done");
@@ -202,13 +199,6 @@ send_command(ide_device_info *device, ide_qrequest *qrequest,
uint8 num_retries = 0;
bool irq_guard;
FAST_LOGN(bus->log, ev_ide_send_command, 15, device->is_device1, (uint32)qrequest,
device->tf.raw.r[0], device->tf.raw.r[1], device->tf.raw.r[2],
device->tf.raw.r[3], device->tf.raw.r[4], device->tf.raw.r[5],
device->tf.raw.r[6],
device->tf.raw.r[7], device->tf.raw.r[8], device->tf.raw.r[9],
device->tf.raw.r[10], device->tf.raw.r[11]);
retry:
irq_guard = bus->num_running_reqs > 1;
@@ -270,7 +260,7 @@ retry:
return false;
}
// write parameters
// write parameters
if (bus->controller->write_command_block_regs(bus->channel_cookie, &device->tf,
device->tf_param_mask) != B_OK)
goto err;
@@ -283,7 +273,7 @@ retry:
// (at my system, up to 30 µs elapsed)
// additionally, old drives (at least my IBM-DTTA-351010) loose
// sync if they are pushed too hard - on heavy overlapped write
// sync if they are pushed too hard - on heavy overlapped write
// stress this drive tends to forget outstanding requests,
// waiting at least 50 µs seems(!) to solve this
while (system_time() - irq_disabled_at < MAX_IRQ_DELAY)
@@ -294,7 +284,7 @@ retry:
// lock the bus before sending; this way, IRQs that are fired
// shortly before/after sending of command are delayed until the
// command is really sent (start_waiting unlocks the bus) and then
// the IRQ handler can check savely whether the IRQ really signals
// the IRQ handler can check savely whether the IRQ really signals
// finishing of command or not by testing the busy-signal of the device
if (new_state != ide_state_accessing) {
IDE_LOCK(bus);
@@ -307,10 +297,10 @@ retry:
goto err1;
}
// write command code - this will start the actual command
// write command code - this will start the actual command
SHOW_FLOW(3, "Writing command 0x%02x", (int)device->tf.write.command);
if (bus->controller->write_command_block_regs(bus->channel_cookie,
&device->tf, ide_mask_command) != B_OK)
&device->tf, ide_mask_command) != B_OK)
goto err1;
// start waiting now; also un-blocks IRQ handler (see above)
@@ -350,7 +340,7 @@ ide_wait(ide_device_info *device, int mask, int not_mask,
bigtime_t elapsed_time;
int status;
// do spin before test as the device needs 400 ns
// do spin before test as the device needs 400 ns
// to update its status register
spin(1);
@@ -391,8 +381,6 @@ device_start_service(ide_device_info *device, int *tag)
{
ide_bus_info *bus = device->bus;
FAST_LOG1(bus->log, ev_ide_device_start_service, device->is_device1);
device->tf.write.command = IDE_CMD_SERVICE;
device->tf.queued.mode = ide_mode_lba;
@@ -433,7 +421,6 @@ device_start_service(ide_device_info *device, int *tag)
*tag = device->tf.queued.tag;
FAST_LOG2(bus->log, ev_ide_device_start_service2, device->is_device1, *tag);
return true;
err:
@@ -450,14 +437,14 @@ check_service_req(ide_device_info *device)
ide_bus_info *bus = device->bus;
int status;
// fast bailout if there is no request pending
// fast bailout if there is no request pending
if (device->num_running_reqs == 0)
return false;
if (bus->active_device != device) {
// don't apply any precautions in terms of IRQ
// -> the bus is in accessing state, so IRQs are ignored anyway
if (bus->controller->write_command_block_regs(bus->channel_cookie,
if (bus->controller->write_command_block_regs(bus->channel_cookie,
&device->tf, ide_mask_device_head) != B_OK)
// on error, pretend that this device asks for service
// -> the disappeared controller will be recognized soon ;)
+11 -20
View File
@@ -9,7 +9,7 @@
Manager of IDE controllers
Whenever a new IDE channel is reported, a new SIM is
registered at the SCSI bus manager.
registered at the SCSI bus manager.
*/
#include "ide_internal.h"
@@ -24,14 +24,14 @@
/** called when an IDE channel was registered by a controller driver */
static status_t
ide_channel_added(device_node_handle parent)
ide_channel_added(device_node *parent)
{
char *controller_name = NULL;
const char *controller_name = NULL;
uint32 channel_id;
SHOW_FLOW0(2, "");
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
if (pnp->get_attr_string(parent, IDE_CONTROLLER_CONTROLLER_NAME_ITEM,
&controller_name, true) != B_OK) {
dprintf("ide: ignored controller - controller name missing\n");
goto err;
@@ -47,10 +47,9 @@ ide_channel_added(device_node_handle parent)
{
device_attr attrs[] =
{
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: IDE_SIM_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_FOR_SIM_MODULE_NAME }},
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ string: controller_name }},
// maximum number of blocks per transmission:
// - ATAPI uses packets, i.e. normal SCSI limits apply
@@ -59,31 +58,23 @@ ide_channel_added(device_node_handle parent)
// - some broken disk's firmware (read: IBM DTTA drives)
// don't like 256 blocks in command queuing mode
// -> use 255 blocks as a least common nominator
// (this is still 127.5K for HDs and 510K for CDs,
// (this is still 127.5K for HDs and 510K for CDs,
// which should be sufficient)
// Note: to fix specific drive bugs, use ide_sim_get_restrictions()
// in ide_sim.c!
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
{ IDE_CHANNEL_ID_ITEM, B_UINT32_TYPE, { ui32: channel_id }},
{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: IDE_CHANNEL_ID_GENERATOR }},
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: channel_id }},
{ NULL }
};
device_node_handle node;
status_t res;
res = pnp->register_device(parent, attrs, NULL, &node);
free(controller_name);
return res;
return pnp->register_node(parent, IDE_SIM_MODULE_NAME, attrs, NULL,
NULL);
}
err:
free(controller_name);
return B_NO_MEMORY;
}
@@ -5,19 +5,12 @@
#ifndef __IDE_INTERNAL_H__
#define __IDE_INTERNAL_H__
/*
Part of Open IDE bus manager
Internal structures
*/
#include <bus/IDE.h>
#include <bus/SCSI.h>
#include "ide_device_infoblock.h"
#include <ide_types.h>
#include <device_manager.h>
#include <fast_log.h>
#define debug_level_error 2
#define debug_level_info 1
@@ -28,24 +21,6 @@
#include "wrapper.h"
//#define USE_FAST_LOG
#ifdef USE_FAST_LOG
#define FAST_LOG0( handle, event ) fast_log->log_0( handle, event )
#define FAST_LOG1( handle, event, param ) fast_log->log_1( handle, event, param )
#define FAST_LOG2( handle, event, param1, param2 ) fast_log->log_2( handle, event, param1, param2 )
#define FAST_LOG3( handle, event, param1, param2, param3 ) fast_log->log_3( handle, event, param1, param2, param3 )
#define FAST_LOGN( handle, event, num_params... ) fast_log->log_n( handle, event, num_params )
#else
#define FAST_LOG0( handle, event )
#define FAST_LOG1( handle, event, param )
#define FAST_LOG2( handle, event, param1, param2 )
#define FAST_LOG3( handle, event, param1, param2, param3 )
#define FAST_LOGN( handle, event, num_params... )
#endif
#define IDE_STD_TIMEOUT 10
#define IDE_RELEASE_TIMEOUT 10000000
@@ -58,7 +33,6 @@
#define IDE_CHANNEL_ID_ITEM "ide/channel_id"
extern device_manager_info *pnp;
extern fast_log_info *fast_log;
typedef struct ide_bus_info ide_bus_info;
@@ -99,7 +73,7 @@ typedef struct ide_device_info {
uint8 queue_depth; // maximum Command Queueing depth
uint8 last_lun; // last LUN
uint8 last_lun; // last LUN
uint8 DMA_failures; // DMA failures in a row
uint8 CQ_failures; // Command Queuing failures during _last_ command
@@ -129,7 +103,7 @@ typedef struct ide_device_info {
// ata from here on
uint64 total_sectors; // size in sectors
// atapi from here on
// atapi from here on
uint8 packet[12]; // atapi command packet
struct {
@@ -154,7 +128,7 @@ typedef struct ide_device_info {
bool has_odd_byte; // remaining odd byte
int odd_byte; // content off odd byte
ide_device_infoblock infoblock; // infoblock of device
ide_device_infoblock infoblock; // infoblock of device
} ide_device_info;
@@ -165,7 +139,7 @@ typedef enum {
ide_request_autosense = 2
} ide_request_state;*/
// ide request
// ide request
typedef struct ide_qrequest {
struct ide_qrequest *next;
ide_device_info *device;
@@ -182,7 +156,7 @@ typedef struct ide_qrequest {
// state of ide bus
typedef enum {
ide_state_idle, // noone is using it, but overlapped
ide_state_idle, // noone is using it, but overlapped
// commands may be pending
ide_state_accessing, // bus is in use
ide_state_async_waiting, // waiting for IRQ, to be reported via irq_dpc
@@ -228,14 +202,13 @@ struct ide_bus_info {
uchar path_id;
device_node_handle node; // our pnp node
device_node *node; // our pnp node
// restrictions, read from controller node
uint8 max_devices;
uint8 can_DMA;
uint8 can_CQ;
fast_log_handle log;
char name[32];
};
@@ -271,7 +244,7 @@ enum {
ev_ide_timeout,
ev_ide_reset_bus,
ev_ide_reset_device,
ev_ide_scsi_io,
ev_ide_scsi_io_exec,
ev_ide_scsi_io_invalid_device,
@@ -280,7 +253,7 @@ enum {
ev_ide_scsi_io_disconnected,
ev_ide_finish_request,
ev_ide_finish_norelease,
ev_ide_scan_device_int,
ev_ide_scan_device_int_cant_send,
ev_ide_scan_device_int_keeps_busy,
@@ -290,12 +263,12 @@ enum {
// get selected device
static inline
ide_device_info *get_current_device(ide_bus_info *bus)
static inline ide_device_info *
get_current_device(ide_bus_info *bus)
{
ide_task_file tf;
bus->controller->read_command_block_regs(bus->channel_cookie, &tf,
bus->controller->read_command_block_regs(bus->channel_cookie, &tf,
ide_mask_device_head);
return bus->devices[tf.lba.device];
@@ -355,7 +328,7 @@ bool send_command(ide_device_info *device, ide_qrequest *qrequest,
bool device_start_service( ide_device_info *device, int *tag);
bool reset_device(ide_device_info *device, ide_qrequest *ignore);
bool reset_bus(ide_device_info *device, ide_qrequest *ignore);
bool check_service_req(ide_device_info *device);
+179 -241
View File
@@ -14,7 +14,7 @@
consists of a single level only. In fact it is no bus manager
in terms of the PnP structure at all but a driver that maps
one SCSI bus onto one IDE controller.
This structure does not allow us to publish IDE devices
as they can be accessed via the SCSI bus node only. Therefore
we do a full bus scan every time the IDE bus node is loaded.
@@ -33,41 +33,6 @@
#include <stdio.h>
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 " },
{ ev_ide_device_start_service, "ev_ide_device_start_service" },
{ ev_ide_device_start_service2, "ev_ide_device_start_service2" },
{ ev_ide_dpc_service, "ev_ide_dpc_service" },
{ ev_ide_dpc_continue, "ev_ide_dpc_continue" },
{ ev_ide_irq_handle, "ev_ide_irq_handle" },
{ ev_ide_cancel_irq_timeout, "ev_ide_cancel_irq_timeout" },
{ ev_ide_start_waiting, "ev_ide_start_waiting" },
{ ev_ide_timeout_dpc, "ev_ide_timeout_dpc" },
{ ev_ide_timeout, "ev_ide_timeout" },
{ ev_ide_reset_bus, "ev_ide_reset_bus" },
{ ev_ide_reset_device, "ev_ide_reset_device" },
{ ev_ide_scsi_io, "ev_ide_scsi_io" },
{ ev_ide_scsi_io_exec, "ev_ide_scsi_io_exec" },
{ ev_ide_scsi_io_invalid_device, "ev_ide_scsi_io_invalid_device" },
{ ev_ide_scsi_io_bus_busy, "ev_ide_scsi_io_bus_busy" },
{ ev_ide_scsi_io_device_busy, "ev_ide_scsi_io_device_busy" },
{ ev_ide_scsi_io_disconnected, "ev_ide_scsi_io_disconnected" },
{ ev_ide_finish_request, "ev_ide_finish_request" },
{ ev_ide_finish_norelease, "ev_ide_finish_norelease" },
{ ev_ide_scan_device_int, "ev_ide_scan_device_int" },
{ ev_ide_scan_device_int_cant_send, "ev_ide_scan_device_int_cant_send" },
{ ev_ide_scan_device_int_keeps_busy, "ev_ide_scan_device_int_keeps_busy" },
{ ev_ide_scan_device_int_found, "ev_ide_scan_device_int_found" },
{}
};
#endif
static void disconnect_worker(ide_bus_info *bus, void *arg);
@@ -85,7 +50,7 @@ is_queuable(ide_device_info *device, scsi_ccb *request)
if (!device->CQ_enabled)
return false;
// make sure the caller allows queuing
// make sure the caller allows queuing
if ((request->flags & SCSI_ORDERED_QTAG) != 0)
return false;
@@ -96,151 +61,6 @@ is_queuable(ide_device_info *device, scsi_ccb *request)
}
static void
sim_scsi_io(ide_bus_info *bus, scsi_ccb *request)
{
ide_device_info *device;
bool queuable;
ide_qrequest *qrequest;
//ide_request_priv *priv;
// FAST_LOG3( bus->log, ev_ide_scsi_io, (uint32)request, request->target_id, request->target_lun );
SHOW_FLOW(3, "%d:%d", request->target_id, request->target_lun);
if (bus->disconnected)
goto err_disconnected;
// make sure, device is valid
// I've read that there are ATAPI devices with more then one LUN,
// but it seems that most (all?) devices ignore LUN, so we have
// to restrict to LUN 0 to avoid mirror devices
if (request->target_id >= 2)
goto err_inv_device;
device = bus->devices[request->target_id];
if (device == NULL)
goto err_inv_device;
if (request->target_lun > device->last_lun)
goto err_inv_device;
queuable = is_queuable(device, request);
// grab the bus
ACQUIRE_BEN(&bus->status_report_ben);
IDE_LOCK(bus);
if (bus->state != ide_state_idle)
goto err_bus_busy;
// bail out if device can't accept further requests
if (device->free_qrequests == NULL
|| (device->num_running_reqs > 0 && !queuable))
goto err_device_busy;
bus->state = ide_state_accessing;
IDE_UNLOCK(bus);
RELEASE_BEN(&bus->status_report_ben);
// as we own the bus, noone can bother us
qrequest = device->free_qrequests;
device->free_qrequests = qrequest->next;
qrequest->request = request;
qrequest->queuable = queuable;
qrequest->running = true;
qrequest->uses_dma = false;
++device->num_running_reqs;
++bus->num_running_reqs;
bus->active_qrequest = qrequest;
FAST_LOGN(bus->log, ev_ide_scsi_io_exec, 4, (uint32)qrequest,
(uint32)request, bus->num_running_reqs, device->num_running_reqs);
device->exec_io(device, qrequest);
return;
err_inv_device:
SHOW_ERROR(3, "Invalid device %d:%d",
request->target_id, request->target_lun);
FAST_LOG1(bus->log, ev_ide_scsi_io_invalid_device, (uint32)request);
request->subsys_status = SCSI_SEL_TIMEOUT;
scsi->finished(request, 1);
return;
err_bus_busy:
SHOW_FLOW0(3, "Bus busy");
FAST_LOG1(bus->log, ev_ide_scsi_io_bus_busy, (uint32)request);
IDE_UNLOCK(bus);
scsi->requeue(request, true);
RELEASE_BEN(&bus->status_report_ben);
return;
err_device_busy:
SHOW_FLOW0(3, "Device busy");
FAST_LOG1(bus->log, ev_ide_scsi_io_device_busy, (uint32)request);
IDE_UNLOCK(bus);
scsi->requeue(request, false);
RELEASE_BEN(&bus->status_report_ben);
return;
err_disconnected:
SHOW_ERROR0(3, "No controller anymore");
FAST_LOG1(bus->log, ev_ide_scsi_io_disconnected, (uint32)request);
request->subsys_status = SCSI_NO_HBA;
scsi->finished(request, 1);
return;
}
static uchar
sim_path_inquiry(ide_bus_info *bus, scsi_path_inquiry *info)
{
char *controller_name;
SHOW_FLOW0(4, "");
if (bus->disconnected)
return SCSI_NO_HBA;
info->hba_inquiry = SCSI_PI_TAG_ABLE | SCSI_PI_WIDE_16;
info->hba_misc = 0;
memset(info->vuhba_flags, 0, sizeof(info->vuhba_flags));
// we don't need any of the private data
info->sim_priv = 0;
// there is no initiator for IDE, but SCSI needs it for scanning
info->initiator_id = 2;
// there's no controller limit, so set it higher then the maximum
// number of queued requests, which is 32 per device * 2 devices
info->hba_queue_size = 65;
strncpy(info->sim_vid, "Haiku", SCSI_SIM_ID);
if (pnp->get_attr_string(bus->node, SCSI_DESCRIPTION_CONTROLLER_NAME,
&controller_name, true) == B_OK) {
strlcpy(info->hba_vid, controller_name, SCSI_HBA_ID);
free(controller_name);
} else
strlcpy(info->hba_vid, "", SCSI_HBA_ID);
strlcpy(info->controller_family, "IDE", SCSI_FAM_ID);
strlcpy(info->controller_type, "IDE", SCSI_TYPE_ID);
SHOW_FLOW0(4, "done");
return SCSI_REQ_CMP;
}
static void
scan_device(ide_bus_info *bus, int device)
{
@@ -274,6 +94,151 @@ sim_scan_bus(ide_bus_info *bus)
}
static void
sim_set_scsi_bus(ide_bus_info *bus, scsi_bus scsi)
{
bus->scsi_cookie = scsi;
// detect devices
sim_scan_bus(bus);
}
static void
sim_scsi_io(ide_bus_info *bus, scsi_ccb *request)
{
ide_device_info *device;
bool queuable;
ide_qrequest *qrequest;
SHOW_FLOW(3, "%d:%d", request->target_id, request->target_lun);
if (bus->disconnected)
goto err_disconnected;
// make sure, device is valid
// I've read that there are ATAPI devices with more then one LUN,
// but it seems that most (all?) devices ignore LUN, so we have
// to restrict to LUN 0 to avoid mirror devices
if (request->target_id >= 2)
goto err_inv_device;
device = bus->devices[request->target_id];
if (device == NULL)
goto err_inv_device;
if (request->target_lun > device->last_lun)
goto err_inv_device;
queuable = is_queuable(device, request);
// grab the bus
ACQUIRE_BEN(&bus->status_report_ben);
IDE_LOCK(bus);
if (bus->state != ide_state_idle)
goto err_bus_busy;
// bail out if device can't accept further requests
if (device->free_qrequests == NULL
|| (device->num_running_reqs > 0 && !queuable))
goto err_device_busy;
bus->state = ide_state_accessing;
IDE_UNLOCK(bus);
RELEASE_BEN(&bus->status_report_ben);
// as we own the bus, noone can bother us
qrequest = device->free_qrequests;
device->free_qrequests = qrequest->next;
qrequest->request = request;
qrequest->queuable = queuable;
qrequest->running = true;
qrequest->uses_dma = false;
++device->num_running_reqs;
++bus->num_running_reqs;
bus->active_qrequest = qrequest;
device->exec_io(device, qrequest);
return;
err_inv_device:
SHOW_ERROR(3, "Invalid device %d:%d",
request->target_id, request->target_lun);
request->subsys_status = SCSI_SEL_TIMEOUT;
scsi->finished(request, 1);
return;
err_bus_busy:
SHOW_FLOW0(3, "Bus busy");
IDE_UNLOCK(bus);
scsi->requeue(request, true);
RELEASE_BEN(&bus->status_report_ben);
return;
err_device_busy:
SHOW_FLOW0(3, "Device busy");
IDE_UNLOCK(bus);
scsi->requeue(request, false);
RELEASE_BEN(&bus->status_report_ben);
return;
err_disconnected:
SHOW_ERROR0(3, "No controller anymore");
request->subsys_status = SCSI_NO_HBA;
scsi->finished(request, 1);
return;
}
static uchar
sim_path_inquiry(ide_bus_info *bus, scsi_path_inquiry *info)
{
const char *controller_name;
SHOW_FLOW0(4, "");
if (bus->disconnected)
return SCSI_NO_HBA;
info->hba_inquiry = SCSI_PI_TAG_ABLE | SCSI_PI_WIDE_16;
info->hba_misc = 0;
memset(info->vuhba_flags, 0, sizeof(info->vuhba_flags));
// we don't need any of the private data
info->sim_priv = 0;
// there is no initiator for IDE, but SCSI needs it for scanning
info->initiator_id = 2;
// there's no controller limit, so set it higher then the maximum
// number of queued requests, which is 32 per device * 2 devices
info->hba_queue_size = 65;
strncpy(info->sim_vid, "Haiku", SCSI_SIM_ID);
if (pnp->get_attr_string(bus->node, SCSI_DESCRIPTION_CONTROLLER_NAME,
&controller_name, true) == B_OK) {
strlcpy(info->hba_vid, controller_name, SCSI_HBA_ID);
} else
strlcpy(info->hba_vid, "", SCSI_HBA_ID);
strlcpy(info->controller_family, "IDE", SCSI_FAM_ID);
strlcpy(info->controller_type, "IDE", SCSI_TYPE_ID);
SHOW_FLOW0(4, "done");
return SCSI_REQ_CMP;
}
static uchar
sim_abort(ide_bus_info *bus, scsi_ccb *ccb_to_abort)
{
@@ -339,7 +304,7 @@ create_sense(ide_device_info *device, scsi_sense *sense)
void
finish_checksense(ide_qrequest *qrequest)
{
SHOW_FLOW(3, "%p, subsys_status=%d, sense=%x",
SHOW_FLOW(3, "%p, subsys_status=%d, sense=%x",
qrequest->request,
qrequest->request->subsys_status,
(int)qrequest->device->new_combined_sense);
@@ -371,7 +336,6 @@ finish_request(ide_qrequest *qrequest, bool resubmit)
scsi_ccb *request;
uint num_running;
FAST_LOG2(bus->log, ev_ide_finish_request, (uint32)qrequest, resubmit);
SHOW_FLOW0(3, "");
// save request first, as qrequest can be reused as soon as
@@ -394,10 +358,10 @@ finish_request(ide_qrequest *qrequest, bool resubmit)
// TBD:
// if we really handle a service request, the finished command
// is delayed unnecessarily, but if we tell the XPT about the finished
// command first, it will instantly try to pass us another
// command first, it will instantly try to pass us another
// request to handle, which we will refuse as the bus is still
// locked; this really has to be improved
access_finished(bus, device);
access_finished(bus, device);
ACQUIRE_BEN(&bus->status_report_ben);
@@ -425,7 +389,7 @@ set_check_condition(ide_qrequest *qrequest)
request->subsys_status = SCSI_REQ_CMP_ERR;
request->device_status = SCSI_STATUS_CHECK_CONDITION;
// copy sense only if caller requested it
if ((request->flags & SCSI_DIS_AUTOSENSE) == 0) {
scsi_sense sense;
@@ -488,8 +452,6 @@ finish_norelease(ide_qrequest *qrequest, bool resubmit)
ide_bus_info *bus = device->bus;
uint num_requests;
FAST_LOG2(bus->log, ev_ide_finish_norelease, (uint32)qrequest, resubmit);
qrequest->running = false;
qrequest->next = device->free_qrequests;
device->free_qrequests = qrequest;
@@ -524,7 +486,7 @@ finish_all_requests(ide_device_info *device, ide_qrequest *ignore,
if (device == NULL)
return;
// we only have to block the device, but for CD changers we
// we only have to block the device, but for CD changers we
// have to block all LUNS of the device (and we neither know
// their device handle nor which exist at all), so block
// the entire bus instead (it won't take that long anyway)
@@ -544,16 +506,15 @@ 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)
ide_sim_init_bus(device_node *node, void **cookie)
{
device_node_handle parent;
ide_bus_info *bus;
bool dmaDisabled = false;
status_t status;
SHOW_FLOW0(3, "");
// first prepare the info structure
// first prepare the info structure
bus = (ide_bus_info *)malloc(sizeof(*bus));
if (bus == NULL)
return B_NO_MEMORY;
@@ -573,18 +534,9 @@ 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);
bus->scsi_cookie = user_cookie;
bus->state = ide_state_idle;
bus->timer.bus = bus;
bus->synced_pc_list = NULL;
@@ -608,7 +560,7 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
}
status = INIT_BEN(&bus->status_report_ben, "ide_status_report");
if (status < B_OK)
if (status < B_OK)
goto err4;
{
@@ -657,36 +609,27 @@ ide_sim_init_bus(device_node_handle node, void *user_cookie, void **cookie)
bus->can_CQ = false;
}
parent = pnp->get_parent(node);
{
device_node *parent = pnp->get_parent_node(node);
pnp->get_driver(parent, (driver_module_info **)&bus->controller,
(void **)&bus->channel_cookie);
status = pnp->init_driver(parent, bus, (driver_module_info **)&bus->controller,
(void **)&bus->channel_cookie);
pnp->put_device_node(parent);
if (status != B_OK)
goto err5;
bus->controller->set_channel(bus->channel_cookie, bus);
pnp->put_node(parent);
}
*cookie = bus;
// detect devices
sim_scan_bus(bus);
return B_OK;
err5:
DELETE_BEN(&bus->status_report_ben);
err4:
delete_sem(bus->scan_device_sem);
err3:
delete_sem(bus->sync_wait_sem);
err2:
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 status;
@@ -696,18 +639,12 @@ err:
static status_t
ide_sim_uninit_bus(ide_bus_info *bus)
{
device_node_handle parent = pnp->get_parent(bus->node);
pnp->uninit_driver(parent);
pnp->put_device_node(parent);
DELETE_BEN(&bus->status_report_ben);
DELETE_BEN(&bus->status_report_ben);
delete_sem(bus->scan_device_sem);
delete_sem(bus->sync_wait_sem);
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);
free(bus);
@@ -732,12 +669,8 @@ disconnect_worker(ide_bus_info *bus, void *arg)
static void
ide_sim_bus_removed(device_node_handle node, ide_bus_info *bus)
{
if (bus == NULL)
// driver not loaded - no manual intervention needed
return;
ide_sim_bus_removed(ide_bus_info *bus)
{
// XPT must not issue further commands
scsi->block_bus(bus->scsi_cookie);
// make sure, we refuse all new commands
@@ -769,9 +702,9 @@ ide_sim_get_restrictions(ide_bus_info *bus, uchar target_id,
*max_blocks = 255;
if (device->is_atapi) {
if (strncmp(device->infoblock.model_number, "IOMEGA ZIP 100 ATAPI",
if (strncmp(device->infoblock.model_number, "IOMEGA ZIP 100 ATAPI",
strlen("IOMEGA ZIP 100 ATAPI")) == 0
|| strncmp( device->infoblock.model_number, "IOMEGA Clik!",
|| strncmp( device->infoblock.model_number, "IOMEGA Clik!",
strlen( "IOMEGA Clik!")) == 0) {
SHOW_ERROR0(2, "Found buggy ZIP/Clik! drive - restricting transmission size");
*max_blocks = 64;
@@ -850,13 +783,18 @@ scsi_sim_interface ide_sim_module = {
std_ops,
},
NULL, // supported devices
NULL, // supported devices
NULL, // register node
(status_t (*)(device_node_handle, void *, void **))ide_sim_init_bus,
(status_t (*)(void *) ) ide_sim_uninit_bus,
(void (*)(device_node_handle, void *)) ide_sim_bus_removed
(status_t (*)(device_node *, void **)) ide_sim_init_bus,
(void (*)(void *)) ide_sim_uninit_bus,
NULL, // register child devices
NULL, // rescan
(void (*)(void *)) ide_sim_bus_removed,
NULL, // suspend
NULL // resume
},
(void (*)(scsi_sim_cookie, scsi_bus)) sim_set_scsi_bus,
(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,
@@ -865,8 +803,8 @@ scsi_sim_interface ide_sim_module = {
(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,
(status_t (*)(scsi_sim_cookie, uint8, uint32, void *, size_t))ide_sim_ioctl,
+10 -21
View File
@@ -38,11 +38,10 @@ ide_dpc(void *arg)
//snooze(500000);
// IRQ handler doesn't tell us whether this bus was in async_wait or
// IRQ handler doesn't tell us whether this bus was in async_wait or
// in idle state, so we just check whether there is an active request,
// which means that we were async_waiting
if (bus->active_qrequest != NULL) {
FAST_LOG1(bus->log, ev_ide_dpc_continue, (uint32)bus->active_qrequest);
TRACE(("continue command\n"));
// cancel timeout
@@ -66,8 +65,6 @@ ide_dpc(void *arg)
// for service requests
TRACE(("irq in idle mode - possible service request\n"));
FAST_LOG0(bus->log, ev_ide_dpc_service);
device = get_current_device(bus);
if (device == NULL) {
// got an interrupt from a non-existing device
@@ -95,7 +92,7 @@ ide_dpc(void *arg)
status_t
ide_irq_handler(ide_bus_info *bus, uint8 status)
{
{
ide_device_info *device;
// we need to lock bus to have a solid bus state
@@ -137,7 +134,7 @@ ide_irq_handler(ide_bus_info *bus, uint8 status)
IDE_UNLOCK(bus);
scsi->schedule_dpc(bus->scsi_cookie, bus->irq_dpc, ide_dpc, bus);
return B_INVOKE_SCHEDULER;
return B_INVOKE_SCHEDULER;
case ide_state_idle:
TRACE(("state: idle, num_running_reqs %d\n", bus->num_running_reqs));
@@ -191,8 +188,6 @@ ide_irq_handler(ide_bus_info *bus, uint8 status)
void
cancel_irq_timeout(ide_bus_info *bus)
{
FAST_LOG0(bus->log, ev_ide_cancel_irq_timeout);
IDE_LOCK(bus);
bus->state = ide_state_accessing;
IDE_UNLOCK(bus);
@@ -210,13 +205,11 @@ start_waiting(ide_bus_info *bus, uint32 timeout, int new_state)
{
int res;
FAST_LOG1(bus->log, ev_ide_start_waiting, new_state);
TRACE(("timeout = %u\n", (uint)timeout));
bus->state = new_state;
res = add_timer(&bus->timer.te, ide_timeout,
res = add_timer(&bus->timer.te, ide_timeout,
(bigtime_t)timeout * 1000000, B_ONE_SHOT_RELATIVE_TIMER);
if (res != B_OK)
@@ -260,8 +253,6 @@ ide_timeout_dpc(void *arg)
dprintf("ide: ide_timeout_dpc() bus %p, device %p\n", bus, device);
FAST_LOG1(bus->log, ev_ide_timeout_dpc, (uint32)qrequest);
// this also resets overlapped commands
reset_device(device, qrequest);
@@ -275,7 +266,7 @@ ide_timeout_dpc(void *arg)
}
}
// let upper layer do the retry
// let upper layer do the retry
finish_checksense(qrequest);
}
@@ -287,14 +278,12 @@ ide_timeout(timer *arg)
{
ide_bus_info *bus = ((ide_bus_timer_info *)arg)->bus;
FAST_LOG0(bus->log, ev_ide_timeout);
TRACE(("ide_timeout(): %p\n", bus));
dprintf("ide: ide_timeout() bus %p\n", bus);
// we need to lock bus to have a solid bus state
// (side effect: we lock out the IRQ handler)
// (side effect: we lock out the IRQ handler)
IDE_LOCK(bus);
switch (bus->state) {
@@ -327,7 +316,7 @@ ide_timeout(timer *arg)
default:
// this case also happens if a timeout fires too late;
// unless there is a bug, the timeout should always be canceled
// unless there is a bug, the timeout should always be canceled
// before declaring bus as being idle
dprintf("BUG: unknown state (%d)\n", (int)bus->state);
@@ -398,7 +387,7 @@ schedule_synced_pc(ide_bus_info *bus, ide_synced_pc *pc, void *arg)
// meanwhile, we may have rejected SCSI commands;
// usually, the XPT resends them once a command
// has finished, but in this case XPT doesn't know
// about our "private" command, so we have to tell about
// about our "private" command, so we have to tell about
// idle bus manually
TRACE(("tell SCSI bus manager about idle bus\n"));
scsi->cont_send_bus(bus->scsi_cookie);
@@ -431,7 +420,7 @@ exec_synced_pcs(ide_bus_info *bus, ide_synced_pc *pc_list)
}
/** finish bus access;
/** finish bus access;
* check if any device wants to service pending commands + execute synced_pc
*/
@@ -466,7 +455,7 @@ access_finished(ide_bus_info *bus, ide_device_info *device)
exec_synced_pcs(bus, synced_pc_list);
// executed synced_pc may have generated other sync_pc,
// executed synced_pc may have generated other sync_pc,
// thus the loop
}
}
+8 -4
View File
@@ -137,6 +137,7 @@ unlock_isa_dma_channel(long channel)
}
#if 0
static status_t
isa_init_driver(device_node_handle node, void *user_cookie, void **cookie)
{
@@ -202,6 +203,7 @@ isa_get_paths(const char ***_bus, const char ***_device)
*_bus = kBus;
*_device = NULL;
}
#endif
static status_t
@@ -232,11 +234,11 @@ static isa_module_info isa_module = {
},
NULL // rescan
},
&isa_read_io_8,
&isa_read_io_8,
&isa_write_io_8,
&isa_read_io_16,
&isa_read_io_16,
&isa_write_io_16,
&isa_read_io_32,
&isa_read_io_32,
&isa_write_io_32,
&ram_address,
&make_isa_dma_table,
@@ -246,6 +248,7 @@ static isa_module_info isa_module = {
&unlock_isa_dma_channel
};
#if 0
static isa2_module_info isa2_module = {
{
{
@@ -278,9 +281,10 @@ static isa2_module_info isa2_module = {
start_isa_dma,
};
#endif
module_info *modules[] = {
(module_info *)&isa_module,
(module_info *)&isa2_module,
// (module_info *)&isa2_module,
NULL
};
+2 -6
View File
@@ -8,15 +8,11 @@ KernelAddon pci :
pci_fixup.cpp
pci_info.cpp
pci_module.c
pci_device.c
kernel_cpp.cpp
pci_root.cpp
pci_device.cpp
: pci_arch_bus_manager.a
;
SEARCH on [ FGristFiles
kernel_cpp.cpp
] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
# pci_info.cpp currently needs pcihdr.h so we make its path available and adds dependency
ObjectHdrs [ FGristFiles pci_info$(SUFOBJ) ]
: [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) preferences devices ] ;
@@ -1,12 +1,22 @@
/*
* Copyright 2007, François Revol <revol@free.fr>.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <arch_platform.h>
#include "pci_priv.h"
#include "pci_private.h"
/*
* As we don't have any real PCI bus in any of the supported m68k platforms,
* As we don't have any real PCI bus in any of the supported m68k platforms,
* we fake one, with hardcoded devices.
* TODO: this doesn't make any sense, as we can't share any drivers, anyway.
* We should better export dedicated bus managers for Zorro etc. busses on
* these systems.
* TODO: actually, there are several PCI boards for the Amiga.
*/
#include "amiga/pci_amiga.h"
@@ -1,6 +1,13 @@
/*
* Copyright 2007, François Revol <revol@free.fr>.
* Distributed under the terms of the MIT License.
*/
#include "pci_io.h"
#include "pci_priv.h"
status_t
pci_io_init()
{
@@ -1,8 +1,14 @@
/*
* Copyright 2006, Ingo Weinhold. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_controller.h"
#include <arch_platform.h>
#include "pci_priv.h"
#include "pci_private.h"
#include "openfirmware/pci_openfirmware.h"
@@ -1,5 +1,12 @@
/*
* Copyright 2006, Ingo Weinhold. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_io.h"
#include "pci_priv.h"
#include "pci_private.h"
status_t
pci_io_init()
@@ -1,6 +1,13 @@
#include "pci_priv.h"
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_private.h"
#include "pci_bios.h"
status_t
pci_bios_init(void)
{
@@ -10,7 +17,7 @@ pci_bios_init(void)
status_t
pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value)
uint8 offset, uint8 size, uint32 *value)
{
return B_ERROR;
}
@@ -18,7 +25,7 @@ pci_bios_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
status_t
pci_bios_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value)
uint8 offset, uint8 size, uint32 value)
{
return B_ERROR;
}
@@ -1,13 +1,12 @@
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include "pci_irq.h"
#include "pci_bios.h"
#include "pci_priv.h"
#include "pci_private.h"
#include "pci_controller.h"
#include "arch_cpu.h"
@@ -36,12 +35,12 @@
spinlock sConfigLock = 0;
static status_t
pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 *value)
{
cpu_status cpu;
status_t status = B_OK;
PCI_LOCK_CONFIG(cpu);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
@@ -59,7 +58,7 @@ pci_mech1_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
break;
}
PCI_UNLOCK_CONFIG(cpu);
return status;
}
@@ -70,7 +69,7 @@ pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
{
cpu_status cpu;
status_t status = B_OK;
PCI_LOCK_CONFIG(cpu);
out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT);
switch (size) {
@@ -88,7 +87,7 @@ pci_mech1_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
break;
}
PCI_UNLOCK_CONFIG(cpu);
return status;
}
@@ -107,7 +106,7 @@ pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
{
cpu_status cpu;
status_t status = B_OK;
PCI_LOCK_CONFIG(cpu);
out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT);
out8(bus, PCI_MECH2_FORWARD_PORT);
@@ -127,7 +126,7 @@ pci_mech2_read_config(void *cookie, uint8 bus, uint8 device, uint8 function,
}
out8(0, PCI_MECH2_ENABLE_PORT);
PCI_UNLOCK_CONFIG(cpu);
return status;
}
@@ -158,7 +157,7 @@ pci_mech2_write_config(void *cookie, uint8 bus, uint8 device, uint8 function,
}
out8(0, PCI_MECH2_ENABLE_PORT);
PCI_UNLOCK_CONFIG(cpu);
return status;
}
@@ -178,7 +177,7 @@ pci_ram_address(const void *physical_address_in_system_memory)
}
pci_controller pci_controller_x86_mech1 =
pci_controller pci_controller_x86_mech1 =
{
.read_pci_config = pci_mech1_read_config,
.write_pci_config = pci_mech1_write_config,
@@ -187,7 +186,7 @@ pci_controller pci_controller_x86_mech1 =
.write_pci_irq = pci_x86_irq_write,
};
pci_controller pci_controller_x86_mech2 =
pci_controller pci_controller_x86_mech2 =
{
.read_pci_config = pci_mech2_read_config,
.write_pci_config = pci_mech2_write_config,
@@ -196,7 +195,7 @@ pci_controller pci_controller_x86_mech2 =
.write_pci_irq = pci_x86_irq_write,
};
pci_controller pci_controller_x86_bios =
pci_controller pci_controller_x86_bios =
{
.read_pci_config = pci_bios_read_config,
.write_pci_config = pci_bios_write_config,
@@ -213,11 +212,11 @@ pci_controller_init(void)
bool search_mech2 = true;
bool search_bios = true;
status_t status;
status = pci_x86_irq_init();
if (status != B_OK)
return status;
// PCI configuration mechanism 1 is the preferred one.
// If it doesn't work, try mechanism 2.
// Finally, try to fallback to PCI BIOS
@@ -249,7 +248,7 @@ pci_controller_init(void)
return pci_controller_add(&pci_controller_x86_bios, NULL);
}
}
dprintf("PCI: no configuration mechanism found\n");
return B_ERROR;
}
@@ -1,6 +1,13 @@
#include "pci_priv.h"
/*
* Copyright 2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "pci_private.h"
#include "arch_cpu.h"
status_t
pci_io_init()
{
+1 -1
View File
@@ -13,7 +13,7 @@
#include "util/kernel_cpp.h"
#include "pci_fixup.h"
#include "pci_priv.h"
#include "pci_private.h"
#include "pci.h"
#define TRACE_CAP(x...) dprintf(x)
@@ -1,239 +0,0 @@
/*
* 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 <malloc.h>
#include <string.h>
#include <stdio.h>
#include "pci.h"
#include "pci_priv.h"
// information about one PCI device
typedef struct pci_device_info {
uint8 bus; // bus number
uint8 device; // device number
uint8 function; // function number
device_node_handle node;
pci_root_info *root; // parent, i.e. PCI root
char name[32]; // name (for fast log)
} pci_device_info;
static uint8
pci_device_read_io_8(pci_device_info *device, int mapped_io_addr)
{
return pci_read_io_8(mapped_io_addr);
}
static void
pci_device_write_io_8(pci_device_info *device, int mapped_io_addr, uint8 value)
{
pci_write_io_8(mapped_io_addr, value);
}
static uint16
pci_device_read_io_16(pci_device_info *device, int mapped_io_addr)
{
return pci_read_io_16(mapped_io_addr);
}
static void
pci_device_write_io_16(pci_device_info *device, int mapped_io_addr, uint16 value)
{
pci_write_io_16(mapped_io_addr, value);
}
static uint32
pci_device_read_io_32(pci_device_info *device, int mapped_io_addr)
{
return pci_read_io_32(mapped_io_addr);
}
static void
pci_device_write_io_32(pci_device_info *device, int mapped_io_addr, uint32 value)
{
pci_write_io_32(mapped_io_addr, value);
}
static uint32
pci_device_read_pci_config(pci_device_info *device, uint8 offset, uint8 size)
{
return device->root->read_pci_config(device->bus, device->device,
device->function, offset, size);
}
static void
pci_device_write_pci_config(pci_device device, uint8 offset, uint8 size, uint32 value)
{
return device->root->write_pci_config(device->bus, device->device,
device->function, offset, size, value);
}
static void *
pci_device_ram_address(pci_device_info *device,
const void *physical_address_in_system_memory)
{
return pci_ram_address(physical_address_in_system_memory);
}
static status_t
pci_device_get_pci_info(pci_device device, struct pci_info *info)
{
int i;
if (device == NULL || info == NULL)
return B_BAD_VALUE;
// TODO: Implement more efficiently!
for (i = 0; pci_get_nth_pci_info(i, info) == B_OK; i++) {
if (device->bus == info->bus && device->device == info->device
&& device->function == info->function) {
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
static status_t
pci_device_find_capability(pci_device device, uchar cap_id, uchar *offset)
{
return pci_find_capability(device->bus, device->device,
device->function, cap_id, offset);
}
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,
pci_device_get_pci_info,
pci_device_find_capability
};
@@ -0,0 +1,185 @@
/*
* Copyright 2004-2008, 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pci.h"
#include "pci_private.h"
// information about one PCI device
struct pci_device {
PCIDev* device;
device_node* node;
};
static uint8
pci_device_read_io_8(pci_device* device, addr_t mappedIOAddress)
{
return pci_read_io_8(mappedIOAddress);
}
static void
pci_device_write_io_8(pci_device* device, addr_t mappedIOAddress,
uint8 value)
{
pci_write_io_8(mappedIOAddress, value);
}
static uint16
pci_device_read_io_16(pci_device* device, addr_t mappedIOAddress)
{
return pci_read_io_16(mappedIOAddress);
}
static void
pci_device_write_io_16(pci_device* device, addr_t mappedIOAddress,
uint16 value)
{
pci_write_io_16(mappedIOAddress, value);
}
static uint32
pci_device_read_io_32(pci_device* device, addr_t mappedIOAddress)
{
return pci_read_io_32(mappedIOAddress);
}
static void
pci_device_write_io_32(pci_device* device, addr_t mappedIOAddress, uint32 value)
{
pci_write_io_32(mappedIOAddress, value);
}
static uint32
pci_device_read_pci_config(pci_device* device, uint8 offset, uint8 size)
{
return gPCI->ReadConfig(device->device, offset, size);
}
static void
pci_device_write_pci_config(pci_device* device, uint8 offset, uint8 size,
uint32 value)
{
gPCI->WriteConfig(device->device, offset, size, value);
}
static void*
pci_device_ram_address(pci_device* device, const void* physicalAddress)
{
return pci_ram_address(physicalAddress);
}
static status_t
pci_device_find_capability(pci_device* device, uint8 capID, uint8* offset)
{
return gPCI->FindCapability(device->device, capID, offset);
}
static void
pci_device_get_pci_info(pci_device* device, struct pci_info* info)
{
if (info == NULL)
return;
*info = device->device->info;
}
static status_t
pci_device_init_driver(device_node* node, void** _cookie)
{
uint32 domain;
uint8 bus, deviceNumber, function;
if (gDeviceManager->get_attr_uint32(node, B_PCI_DEVICE_DOMAIN, &domain,
false) != B_OK
|| gDeviceManager->get_attr_uint8(node, B_PCI_DEVICE_BUS, &bus,
false) != B_OK
|| gDeviceManager->get_attr_uint8(node, B_PCI_DEVICE_DEVICE,
&deviceNumber, false) != B_OK
|| gDeviceManager->get_attr_uint8(node, B_PCI_DEVICE_FUNCTION,
&function, false) != B_OK)
return B_ERROR;
pci_device* device = (pci_device*)malloc(sizeof(*device));
if (device == NULL)
return B_NO_MEMORY;
device->device = gPCI->FindDevice(domain, bus, deviceNumber, function);
device->node = node;
*_cookie = device;
return B_OK;
}
static void
pci_device_uninit_driver(void* cookie)
{
pci_device* device = (pci_device*)cookie;
free(device);
}
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, // register child devices
NULL, // rescan devices
NULL, // device removed
},
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_ram_address,
pci_device_read_pci_config,
pci_device_write_pci_config,
pci_device_find_capability,
pci_device_get_pci_info
};
@@ -1,7 +1,7 @@
/*
** Copyright 2003-2006, Marcus Overhagen. All rights reserved.
** Distributed under the terms of the MIT License.
*/
/*
* Copyright 2003-2006, Marcus Overhagen. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
@@ -9,7 +9,7 @@
#include <PCI.h>
#include <string.h>
#include "pci_info.h"
#include "pci_priv.h"
#include "pci_private.h"
#include "pci.h"
#define PCI_VERBOSE 1
@@ -98,7 +98,7 @@ print_capabilities(const pci_info *info)
int i;
TRACE(("PCI: Capabilities: "));
status = pci_read_config(info->bus, info->device, info->function, PCI_status, 2);
if (!(status & PCI_status_capabilities)) {
TRACE(("(not supported)\n"));
@@ -173,7 +173,7 @@ print_info_basic(const pci_info *info, bool verbose)
}
const char *devShort;
const char *devFull;
get_device_info(info->vendor_id, info->device_id, info->u.h0.subsystem_vendor_id, info->u.h0.subsystem_id,
get_device_info(info->vendor_id, info->device_id, info->u.h0.subsystem_vendor_id, info->u.h0.subsystem_id,
&devShort, &devFull);
if (!devShort && !devFull) {
TRACE(("PCI: device %04x: Unknown\n", info->device_id));
@@ -189,7 +189,7 @@ print_info_basic(const pci_info *info, bool verbose)
}
TRACE(("PCI: line_size %02x, latency %02x, header_type %02x, BIST %02x\n",
info->line_size, info->latency, info->header_type, info->bist));
switch (info->header_type & PCI_header_type_mask) {
case PCI_header_type_generic:
print_generic_info(info, verbose);
@@ -1,20 +1,14 @@
/*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2005-2008, 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 <KernelExport.h>
#include <device_manager.h>
#include <bus_manager.h>
#include <PCI.h>
#include <string.h>
#include <stdlib.h>
#include "pci_priv.h"
#include "pci_private.h"
#include "pci_info.h"
#include "pci.h"
@@ -22,139 +16,6 @@
device_manager_info *gDeviceManager;
// 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)
{
char *bus;
// 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;
}
free(bus);
return 1.0;
}
static status_t
pci_module_register_device(device_node_handle parent)
{
// XXX how do we handle this for PPC?
// I/O port for PCI config space address
#define PCI_CONFIG_ADDRESS 0xcf8
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);
}
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" }},
{ B_DRIVER_MAPPING, B_STRING_TYPE, { string: "%"PCI_DEVICE_VENDOR_ID_ITEM "%|_%" PCI_DEVICE_DEVICE_ID_ITEM "%" }},
// ToDo: this is a hack
{ B_DRIVER_DEVICE_TYPE, B_STRING_TYPE, { string: device.class_base == PCI_mass_storage ? "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;
}
static void
pci_module_get_paths(const char ***_bus, const char ***_device)
{
static const char *kBus[] = {"root", NULL};
*_bus = kBus;
*_device = NULL;
}
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, ...)
{
@@ -162,15 +23,15 @@ pci_old_module_std_ops(int32 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;
}
@@ -180,26 +41,7 @@ pci_old_module_std_ops(int32 op, ...)
return B_OK;
}
return B_BAD_VALUE;
}
static int32
pci_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
module_info *module;
return get_module(B_PCI_MODULE_NAME, &module);
// this serializes our module initialization
}
case B_MODULE_UNINIT:
return put_module(B_PCI_MODULE_NAME);
}
return B_BAD_VALUE;
return B_BAD_VALUE;
}
@@ -225,32 +67,6 @@ static struct pci_module_info sOldPCIModule = {
&pci_find_capability
};
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_read_config,
&pci_write_config
};
module_dependency module_dependencies[] = {
{B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager},
{}
@@ -258,7 +74,7 @@ module_dependency module_dependencies[] = {
module_info *modules[] = {
(module_info *)&sOldPCIModule,
(module_info *)&sPCIModule,
(module_info *)&gPCIRootModule,
(module_info *)&gPCIDeviceModule,
NULL
};
@@ -1,5 +1,5 @@
/*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2003-2006, Marcus Overhagen. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -14,7 +14,7 @@
// name of PCI device modules
#define PCI_DEVICE_MODULE_NAME "bus_managers/pci/device_v1"
#define PCI_DEVICE_MODULE_NAME "bus_managers/pci/driver_v1"
extern device_manager_info *gDeviceManager;
@@ -22,8 +22,8 @@ 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;
typedef struct pci_root_module_info {
driver_module_info info;
// read PCI config space
uint32 (*read_pci_config)(uint8 bus, uint8 device, uint8 function,
@@ -32,8 +32,9 @@ typedef struct pci_root_info {
// write PCI config space
void (*write_pci_config)(uint8 bus, uint8 device, uint8 function,
uint8 offset, uint8 size, uint32 value);
} pci_root_info;
} pci_root_module_info;
extern pci_root_module_info gPCIRootModule;
extern pci_device_module_info gPCIDeviceModule;
@@ -0,0 +1,149 @@
/*
* Copyright 2005-2008, 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 <device_manager.h>
#include <PCI.h>
#include <string.h>
#include "pci_private.h"
#include "pci.h"
// name of PCI root module
#define PCI_ROOT_MODULE_NAME "bus_managers/pci/root/driver_v1"
static float
pci_root_supports_device(device_node* parent)
{
// make sure parent is really device root
const char* bus;
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
return B_ERROR;
if (strcmp(bus, "root"))
return 0.0;
return 1.0;
}
static status_t
pci_root_register_device(device_node* parent)
{
// XXX how do we handle this for PPC?
// I/O port for PCI config space address
#define PCI_CONFIG_ADDRESS 0xcf8
io_resource resources[2] = {
{B_IO_PORT, PCI_CONFIG_ADDRESS, 8},
{}
};
device_attr attrs[] = {
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
{B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_KEEP_DRIVER_LOADED}},
{}
};
return gDeviceManager->register_node(parent, PCI_ROOT_MODULE_NAME, attrs,
resources, NULL);
}
static status_t
pci_root_register_child_devices(void* cookie)
{
device_node* node = (device_node*)cookie;
pci_info info;
for (int32 i = 0; pci_get_nth_pci_info(i, &info) == B_OK; i++) {
int domain;
uint8 bus;
if (gPCI->ResolveVirtualBus(info.bus, &domain, &bus) != B_OK) {
dprintf("FAILED!!!!\n");
continue;
}
device_attr attrs[] = {
// info about device
{B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
// location on PCI bus
{B_PCI_DEVICE_DOMAIN, B_UINT32_TYPE, {ui8: domain}},
{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: info.device}},
{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: info.function}},
// info about the device
{B_DEVICE_VENDOR_ID, B_UINT16_TYPE, { ui16: info.vendor_id }},
{B_DEVICE_ID, B_UINT16_TYPE, { ui16: info.device_id }},
{B_DEVICE_TYPE, B_UINT16_TYPE, { ui16: info.class_base }},
{B_DEVICE_SUB_TYPE, B_UINT16_TYPE, { ui16: info.class_sub }},
{B_DEVICE_INTERFACE, B_UINT16_TYPE, { ui16: info.class_api }},
{B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_FIND_CHILD_ON_DEMAND}},
{}
};
gDeviceManager->register_node(node, PCI_DEVICE_MODULE_NAME, attrs,
NULL, NULL);
}
return B_OK;
}
static status_t
pci_root_init(device_node* node, void** _cookie)
{
*_cookie = node;
return B_OK;
}
static int32
pci_root_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
module_info *module;
return get_module(B_PCI_MODULE_NAME, &module);
// this serializes our module initialization
}
case B_MODULE_UNINIT:
return put_module(B_PCI_MODULE_NAME);
}
return B_BAD_VALUE;
}
struct pci_root_module_info gPCIRootModule = {
{
{
PCI_ROOT_MODULE_NAME,
0,
pci_root_std_ops
},
pci_root_supports_device,
pci_root_register_device,
pci_root_init,
NULL, // uninit
pci_root_register_child_devices,
NULL, // rescan devices
NULL, // device removed
},
&pci_read_config,
&pci_write_config
};
+36 -109
View File
@@ -3,54 +3,41 @@
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI bus manager
Devfs entry for raw bus access.
This interface will go away. It's used by scsi_probe as
long as we have no proper pnpfs where all the info can
be retrieved from.
*/
//! Devfs entry for raw bus access.
#include "scsi_internal.h"
#include <device/scsi_bus_raw_driver.h>
#include <pnp_devfs.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <device/scsi_bus_raw_driver.h>
// info about bus
// (used both as bus cookie and file handle cookie)
typedef struct bus_raw_info {
scsi_bus_interface *interface;
scsi_bus cookie;
device_node_handle node;
device_node *node;
} bus_raw_info;
static status_t
scsi_bus_raw_init_device(device_node_handle node,
void *userCookie, void **cookie)
scsi_bus_raw_init(device_node *node, void **cookie)
{
device_node_handle parent = pnp->get_parent(node);
device_node *parent;
bus_raw_info *bus;
scsi_bus_interface *interface;
scsi_bus bus_cookie;
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;
bus = malloc(sizeof(*bus));
bus->interface = interface;
bus->cookie = bus_cookie;
if (bus == NULL)
return B_NO_MEMORY;
parent = pnp->get_parent_node(node);
pnp->get_driver(parent,
(driver_module_info **)&bus->interface, (void **)&bus->cookie);
pnp->put_node(parent);
bus->node = node;
*cookie = bus;
@@ -58,64 +45,19 @@ scsi_bus_raw_init_device(device_node_handle node,
}
static status_t
scsi_bus_raw_uninit_device(bus_raw_info *bus)
static void
scsi_bus_raw_uninit(void *bus)
{
device_node_handle parent = pnp->get_parent(bus->node);
status_t status = pnp->uninit_driver(parent);
pnp->put_device_node(parent);
if (status != B_OK)
return status;
free(bus);
return B_OK;
}
static status_t
scsi_bus_raw_probe(device_node_handle parent)
{
uint8 path_id;
char *name;
if (pnp->get_attr_uint8(parent, SCSI_BUS_PATH_ID_ITEM, &path_id, false) != B_OK)
return B_ERROR;
// put that on heap to not overflow the limited kernel stack
name = malloc(PATH_MAX + 1);
if (name == NULL)
return B_NO_MEMORY;
snprintf(name, PATH_MAX + 1, "bus/scsi/%d/bus_raw", path_id);
{
device_attr attributes[] = {
{ 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_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
{}
};
device_node_handle node;
status_t res = pnp->register_device(parent, attributes, NULL, &node);
free(name);
return res;
}
}
static status_t
scsi_bus_raw_open(bus_raw_info *bus, uint32 flags,
bus_raw_info **handle_cookie)
scsi_bus_raw_open(void *bus, const char *path, uint32 flags,
void **handle_cookie)
{
*handle_cookie = bus;
return B_ERROR;
return B_OK;
}
@@ -129,14 +71,15 @@ scsi_bus_raw_close(void *cookie)
static status_t
scsi_bus_raw_free(void *cookie)
{
return B_ERROR;
return B_OK;
}
static status_t
scsi_bus_raw_control(bus_raw_info *bus, uint32 op, void *data,
size_t len)
scsi_bus_raw_control(void *_cookie, int32 op, void *data, size_t length)
{
bus_raw_info *bus = _cookie;
switch (op) {
case B_SCSI_BUS_RAW_RESET:
return bus->interface->reset_bus(bus->cookie);
@@ -167,40 +110,24 @@ scsi_bus_raw_write(void *cookie, off_t position,
}
static status_t
std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
pnp_devfs_driver_info scsi_bus_raw_module = {
struct device_module_info gSCSIBusRawModule = {
{
{
SCSI_BUS_RAW_MODULE_NAME,
0,
std_ops
},
NULL,
scsi_bus_raw_probe,
scsi_bus_raw_init_device,
(status_t (*) (void *))scsi_bus_raw_uninit_device,
NULL,
SCSI_BUS_RAW_MODULE_NAME,
0,
NULL
},
(status_t (*) (void *, uint32, void **))scsi_bus_raw_open,
scsi_bus_raw_init,
scsi_bus_raw_uninit,
NULL, // removed
scsi_bus_raw_open,
scsi_bus_raw_close,
scsi_bus_raw_free,
(status_t (*) (void *, uint32, void *, size_t))scsi_bus_raw_control,
scsi_bus_raw_read,
scsi_bus_raw_write
scsi_bus_raw_write,
NULL, // io
scsi_bus_raw_control,
NULL, // select
NULL // deselect
};
+27 -43
View File
@@ -10,7 +10,7 @@
Whenever a controller driver publishes a new controller, a new SCSI bus
for public and internal use is registered in turn. After that, this
bus is told to rescan for devices. For each device, there is a
bus is told to rescan for devices. For each device, there is a
device registered for peripheral drivers. (see devices.c)
*/
@@ -63,7 +63,7 @@ scsi_service_threadproc(void *arg)
while (true) {
// we handle multiple requests in scsi_do_service at once;
// to save time, we will acquire all notifications that are sent
// up to now at once.
// up to now at once.
// (Sadly, there is no "set semaphore to zero" function, so this
// is a poor-man emulation)
acquire_sem_etc(bus->start_service, processed_notifications + 1, 0, 0);
@@ -76,16 +76,16 @@ scsi_service_threadproc(void *arg)
// get number of notifications _before_ servicing to make sure no new
// notifications are sent after do_service()
get_sem_count(bus->start_service, &processed_notifications);
scsi_do_service(bus);
}
return 0;
}
static scsi_bus_info *
scsi_create_bus(device_node_handle node, uint8 path_id)
scsi_create_bus(device_node *node, uint8 path_id)
{
scsi_bus_info *bus;
int res;
@@ -150,11 +150,9 @@ err1:
scsi_uninit_ccb_alloc(bus);
err2:
DELETE_BEN(&bus->mutex);
err3:
err3:
delete_sem(bus->start_service);
err4:
//scsi_destroy_device(bus->global_device);
//err5:
delete_sem(bus->scan_lun_lock);
err6:
free(bus);
@@ -165,7 +163,7 @@ err6:
static status_t
scsi_destroy_bus(scsi_bus_info *bus)
{
int32 retcode;
int32 retcode;
// noone is using this bus now, time to clean it up
bus->shutting_down = true;
@@ -184,9 +182,8 @@ scsi_destroy_bus(scsi_bus_info *bus)
static status_t
scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
scsi_init_bus(device_node *node, void **cookie)
{
device_node_handle parent;
uint8 path_id;
scsi_bus_info *bus;
status_t res;
@@ -244,15 +241,14 @@ scsi_init_bus(device_node_handle node, void *user_cookie, void **cookie)
goto err;
}
parent = pnp->get_parent(node);
{
device_node *parent = pnp->get_parent_node(node);
pnp->get_driver(parent, (driver_module_info **)&bus->interface,
(void **)&bus->sim_cookie);
pnp->put_node(parent);
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;
bus->interface->set_scsi_bus(bus->sim_cookie, bus);
}
// cache inquiry data
scsi_inquiry_path(bus, &bus->inquiry_data);
@@ -271,16 +267,10 @@ err:
}
static status_t
static void
scsi_uninit_bus(scsi_bus_info *bus)
{
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;
}
@@ -288,7 +278,6 @@ uchar
scsi_inquiry_path(scsi_bus bus, scsi_path_inquiry *inquiry_data)
{
SHOW_FLOW(4, "path_id=%d", bus->path_id);
return bus->interface->path_inquiry(bus->sim_cookie, inquiry_data);
}
@@ -302,20 +291,18 @@ scsi_reset_bus(scsi_bus_info *bus)
static status_t
scsi_bus_module_init(void)
{
{
SHOW_FLOW0(4, "");
return init_temp_sg();
}
static status_t
scsi_bus_module_uninit(void)
{
{
SHOW_INFO0(4, "");
uninit_temp_sg();
uninit_temp_sg();
return B_OK;
}
@@ -338,19 +325,16 @@ std_ops(int32 op, ...)
scsi_bus_interface scsi_bus_module = {
{
{
{
SCSI_BUS_MODULE_NAME,
0,
std_ops
},
NULL, // supported devices
NULL, // register node
scsi_init_bus,
(status_t (*)(void *))scsi_uninit_bus,
NULL
SCSI_BUS_MODULE_NAME,
0,
std_ops
},
NULL, // supported devices
NULL, // register node
scsi_init_bus,
(void (*)(void *))scsi_uninit_bus,
(status_t (*)(void *))scsi_scan_bus,
(status_t (*)(void *))scsi_scan_bus,
NULL
},
@@ -27,12 +27,12 @@ static bool
scsi_scan_send_tur(scsi_ccb *worker_req)
{
scsi_cmd_tur *cmd = (scsi_cmd_tur *)worker_req->cdb;
SHOW_FLOW0( 3, "" );
memset( cmd, 0, sizeof( *cmd ));
cmd->opcode = SCSI_OP_TEST_UNIT_READY;
worker_req->sg_list = NULL;
worker_req->data = NULL;
worker_req->data_length = 0;
@@ -40,11 +40,11 @@ scsi_scan_send_tur(scsi_ccb *worker_req)
worker_req->timeout = 0;
worker_req->sort = -1;
worker_req->flags = SCSI_DIR_NONE;
scsi_sync_io( worker_req );
SHOW_FLOW( 3, "status=%x", worker_req->subsys_status );
// as this command was only for syncing, we ignore almost all errors
switch (worker_req->subsys_status) {
case SCSI_SEL_TIMEOUT:
@@ -93,7 +93,7 @@ scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data)
SHOW_FLOW0(3, "send successfully");
// we could check transmission length here, but as we reset
// we could check transmission length here, but as we reset
// missing bytes before, we get kind of valid data anyway (hopefully)
strlcpy(vendor, new_inquiry_data->vendor_ident, sizeof(vendor));
@@ -101,10 +101,10 @@ scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data)
strlcpy(rev, new_inquiry_data->product_rev, sizeof(rev));
SHOW_INFO(3, "device type: %d, qualifier: %d, removable: %d, ANSI version: %d, response data format: %d\n"
"vendor: %s, product: %s, rev: %s",
"vendor: %s, product: %s, rev: %s",
new_inquiry_data->device_type, new_inquiry_data->device_qualifier,
new_inquiry_data->removable_medium, new_inquiry_data->ansi_version,
new_inquiry_data->response_data_format,
new_inquiry_data->response_data_format,
vendor, product, rev);
SHOW_INFO(3, "additional_length: %d", new_inquiry_data->additional_length + 4);
@@ -113,7 +113,7 @@ scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data)
// unfortunately, ATAPI CD-ROM drives tend to tell that they have
// only minimal info (36 bytes), but still they return (valid!) 96 bytes -
// bad luck
if (min(cmd->allocation_length, new_inquiry_data->additional_length + 4)
if (min(cmd->allocation_length, new_inquiry_data->additional_length + 4)
>= (int)offsetof(scsi_res_inquiry, version_descriptor[9])) {
int i, previousStandard = -1;
@@ -121,7 +121,7 @@ scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data)
int standard = B_BENDIAN_TO_HOST_INT16(
new_inquiry_data->version_descriptor[i]);
// omit standards reported twice
// omit standards reported twice
if (standard != previousStandard && standard != 0)
SHOW_INFO(3, "standard: %04x", standard);
@@ -133,17 +133,17 @@ scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data)
/* {
unsigned int i;
for( i = 0; i < worker_req->data_length - worker_req->data_resid; ++i ) {
dprintf( "%2x ", *((char *)new_inquiry_data + i) );
}
dprintf( "\n" );
}*/
return true;
}
default:
return false;
}
@@ -196,11 +196,11 @@ scsi_scan_lun(scsi_bus_info *bus, uchar target_id, uchar target_lun)
found = scsi_scan_get_inquiry(worker_req, &new_inquiry_data)
&& new_inquiry_data.device_qualifier == scsi_periph_qual_connected;
// get rid of temporary device - as soon as the device is
// registered, it can be loaded, and we don't want two data
// get rid of temporary device - as soon as the device is
// registered, it can be loaded, and we don't want two data
// structures for one device (the temporary and the official one)
scsi_free_ccb(worker_req);
scsi_put_forced_device(device);
scsi_put_forced_device(device);
if (!found) {
// TBD: better error code, s.a.
@@ -208,17 +208,17 @@ scsi_scan_lun(scsi_bus_info *bus, uchar target_id, uchar target_lun)
}
// !danger!
// if a new device is detected on the same connection, all connections
// if a new device is detected on the same connection, all connections
// to the old device are disabled;
// scenario: you plug in a device, scan the bus, replace the device and then
// scenario: you plug in a device, scan the bus, replace the device and then
// open it; in this case, the connection seems to be to the old device, but really
// is to the new one; if you scan the bus now, the opened connection is disabled
// - bad luck -
// solution 1: scan device during each scsi_init_device
// disadvantage: it takes time and we had to submit commands during the load
// disadvantage: it takes time and we had to submit commands during the load
// sequence, which could lead to deadlocks
// solution 2: device drivers must scan devices before first use
// disadvantage: it takes time and driver must perform a task that
// disadvantage: it takes time and driver must perform a task that
// the bus_manager should really take care of
scsi_register_device(bus, target_id, target_lun, &new_inquiry_data);
@@ -239,9 +239,9 @@ scsi_scan_bus(scsi_bus_info *bus)
int initiator_id, target_id;
scsi_path_inquiry inquiry;
uchar res;
SHOW_FLOW0( 3, "" );
// get ID of initiator (i.e. controller)
res = scsi_inquiry_path(bus, &inquiry);
if (res != SCSI_REQ_CMP)
+53 -109
View File
@@ -6,7 +6,7 @@
*/
/*
Device node layer.
Device node layer.
When a SCSI bus is registered, this layer scans for SCSI devices
and registers a node for each of them. Peripheral drivers are on
@@ -22,25 +22,9 @@
#include <stdio.h>
#ifdef USE_FAST_LOG
static fast_log_event_type scsi_device_events[] = {
{ ev_scsi_requeue_request, "ev_scsi_requeue_request" },
{ ev_scsi_resubmit_request, "ev_scsi_resubmit_request" },
{ ev_scsi_submit_autosense, "ev_scsi_submit_autosense" },
{ ev_scsi_finish_autosense, "ev_scsi_finish_autosense" },
{ ev_scsi_device_queue_overflow, "ev_scsi_device_queue_overflow" },
{ ev_scsi_request_finished, "ev_scsi_request_finished" },
{ ev_scsi_async_io, "ev_scsi_async_io" },
{ ev_scsi_do_resend_request, "ev_scsi_do_resend_request" },
{ ev_copy_sg_data, "ev_copy_sg_data" },
{}
};
#endif
/** free autosense request of device */
static void
static void
scsi_free_autosense_request(scsi_device_info *device)
{
SHOW_FLOW0( 3, "" );
@@ -59,7 +43,7 @@ scsi_free_autosense_request(scsi_device_info *device)
/** free all data of device */
static void
static void
scsi_free_device(scsi_device_info *device)
{
SHOW_FLOW0( 3, "" );
@@ -74,20 +58,15 @@ scsi_free_device(scsi_device_info *device)
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
/** 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
static void
beautify_string(char *dst, char *src, int dst_size)
{
int i;
@@ -114,8 +93,8 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
SHOW_FLOW0( 3, "" );
// ask for restrictions
bus->interface->get_restrictions(bus->sim_cookie,
// ask for restrictions
bus->interface->get_restrictions(bus->sim_cookie,
target_id, &is_atapi, &manual_autosense, &max_blocks);
if (target_lun != 0)
dprintf("WARNING: SCSI target %d lun %d getting restrictions without lun\n",
@@ -123,7 +102,7 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
// find maximum transfer blocks
// set default value to max (need something like ULONG_MAX here)
orig_max_blocks = ~0;
orig_max_blocks = ~0;
pnp->get_attr_uint32(bus->node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &orig_max_blocks, true);
max_blocks = min(max_blocks, orig_max_blocks);
@@ -133,18 +112,12 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
char product_ident[sizeof( inquiry_data->product_ident ) + 1];
char product_rev[sizeof( inquiry_data->product_rev ) + 1];
device_attr attrs[] = {
// info about driver
{ 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,
{ SCSI_DEVICE_INQUIRY_ITEM, B_RAW_TYPE,
{ raw: { inquiry_data, sizeof( *inquiry_data ) }}},
// some more info for driver loading
@@ -154,8 +127,7 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
{ SCSI_DEVICE_REVISION_ITEM, B_STRING_TYPE, { string: product_rev }},
// description of peripheral drivers
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "scsi" }},
// ToDo: mapping is missing
{ B_DEVICE_BUS, B_STRING_TYPE, { string: "scsi" }},
// extra restriction of maximum number of blocks per transfer
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
@@ -166,16 +138,13 @@ scsi_register_device(scsi_bus_info *bus, uchar target_id,
{ SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, B_UINT8_TYPE, { ui8: manual_autosense }},
{ NULL }
};
device_node_handle node;
status_t res;
beautify_string(vendor_ident, inquiry_data->vendor_ident, sizeof(vendor_ident));
beautify_string(product_ident, inquiry_data->product_ident, sizeof(product_ident));
beautify_string(product_rev, inquiry_data->product_rev, sizeof(product_rev));
res = pnp->register_device(bus->node, attrs, NULL, &node);
if (res < 0)
return res;
return pnp->register_node(bus->node, SCSI_DEVICE_MODULE_NAME, attrs,
NULL, NULL);
}
return B_OK;
@@ -184,7 +153,7 @@ 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 *node, scsi_bus_info *bus,
int target_id, int target_lun)
{
scsi_device_info *device;
@@ -228,11 +197,11 @@ err:
/** prepare autosense request.
* this cannot be done on demand but during init as we may
* this cannot be done on demand but during init as we may
* have run out of ccbs when we need it
*/
static status_t
static status_t
scsi_create_autosense_request(scsi_device_info *device)
{
scsi_ccb *request;
@@ -259,22 +228,22 @@ scsi_create_autosense_request(scsi_device_info *device)
request->data_length = SCSI_MAX_SENSE_SIZE;
request->sg_list = (physical_entry *)(buffer + SCSI_MAX_SENSE_SIZE);
request->sg_count = 1;
get_memory_map(buffer, SCSI_MAX_SENSE_SIZE,
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
// buffer is/must be DMA safe as we cannot risk trouble with
// dynamically allocated DMA buffer
request->flags = SCSI_DIR_IN | SCSI_DIS_AUTOSENSE |
request->flags = SCSI_DIR_IN | SCSI_DIS_AUTOSENSE |
SCSI_ORDERED_QTAG | SCSI_DMA_SAFE;
cmd = (scsi_cmd_request_sense *)request->cdb;
request->cdb_length = sizeof(*cmd);
memset(cmd, 0, sizeof(*cmd));
cmd->opcode = SCSI_OP_REQUEST_SENSE;
cmd->opcode = SCSI_OP_REQUEST_SENSE;
cmd->lun = device->target_lun;
cmd->allocation_length = SCSI_MAX_SENSE_SIZE;
@@ -289,15 +258,13 @@ err:
#define SET_BIT(field, bit) field[(bit) >> 3] |= 1 << ((bit) & 7)
static status_t
scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
scsi_init_device(device_node *node, void **cookie)
{
device_node_handle parent = pnp->get_parent(node);
scsi_res_inquiry *inquiry_data = NULL;
const scsi_res_inquiry *inquiry_data = NULL;
uint8 target_id, target_lun, path_id;
scsi_bus_info *bus;
scsi_device_info *device;
status_t res;
driver_module_info *bus_interface;
size_t inquiry_data_len;
uint8 is_atapi, manual_autosense;
@@ -308,41 +275,29 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
|| pnp->get_attr_uint8( node, SCSI_DEVICE_IS_ATAPI_ITEM, &is_atapi, false) != B_OK
|| pnp->get_attr_uint8( node, SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM, &manual_autosense, false) != B_OK
|| pnp->get_attr_raw( node, SCSI_DEVICE_INQUIRY_ITEM,
(void **)&inquiry_data, &inquiry_data_len, false) != B_OK
(const void **)&inquiry_data, &inquiry_data_len, false) != B_OK
|| inquiry_data_len != sizeof(*inquiry_data)) {
res = B_ERROR;
goto err1;
return B_ERROR;
}
res = pnp->init_driver(parent, NULL, &bus_interface,
(void **)&bus);
if (res != B_OK)
goto err1;
{
device_node *parent = pnp->get_parent_node(node);
pnp->get_driver(parent, NULL, (void **)&bus);
pnp->put_node(parent);
}
device = scsi_create_device(node, bus, target_id, target_lun);
if (device == NULL) {
res = B_NO_MEMORY;
goto err2;
}
if (device == NULL)
return B_NO_MEMORY;
// never mind if there is no path - it might be an emulated controller
path_id = -1;
pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true);
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 err3;
}
#endif
device->inquiry_data = *inquiry_data;
// save restrictions
// save restrictions
device->is_atapi = is_atapi;
device->manual_autosense = manual_autosense;
@@ -365,14 +320,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 err3;
goto err;
}
}
// 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 err3;
goto err;
}
memset(device->emulation_map, 0, sizeof(device->emulation_map));
@@ -385,42 +340,27 @@ scsi_init_device(device_node_handle node, void *user_cookie, void **cookie)
SET_BIT(device->emulation_map, SCSI_OP_INQUIRY);
}
free(inquiry_data);
*cookie = device;
return B_OK;
err3:
err:
scsi_free_device(device);
err2:
pnp->uninit_driver(parent);
err1:
pnp->put_device_node(parent);
free(inquiry_data);
return res;
}
static status_t
static void
scsi_uninit_device(scsi_device_info *device)
{
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->uninit_driver(parent);
pnp->put_device_node(parent);
return B_OK;
}
static void
scsi_device_removed(device_node_handle node, scsi_device_info *device)
{
scsi_device_removed(scsi_device_info *device)
{
SHOW_FLOW0(3, "");
if (device == NULL)
@@ -445,9 +385,9 @@ scsi_force_get_device(scsi_bus_info *bus, uchar target_id,
{ SCSI_DEVICE_TARGET_LUN_ITEM, B_UINT8_TYPE, { ui8: target_lun }},
{ NULL }
};
device_node_handle node;
device_node *node;
status_t res;
driver_module_info *driver_interface;
driver_module_info *driver_interface;
scsi_device device;
SHOW_FLOW0(3, "");
@@ -457,15 +397,16 @@ scsi_force_get_device(scsi_bus_info *bus, uchar target_id,
// check whether device registered already
node = NULL;
pnp->get_next_child_device(bus->node, &node, attrs);
pnp->get_next_child_node(bus->node, attrs, &node);
SHOW_FLOW(3, "%p", node);
if (node != NULL) {
// TODO: have a second look a this one!
// there is one - get it
res = pnp->init_driver(node, NULL, &driver_interface,
(void **)&device);
pnp->put_device_node(node);
res = pnp->get_driver(node, &driver_interface, (void **)&device);
if (res != B_OK)
pnp->put_node(node);
} else {
// device doesn't exist yet - create a temporary one
device = scsi_create_device(NULL, bus, target_id, target_lun);
@@ -495,12 +436,13 @@ scsi_put_forced_device(scsi_device_info *device)
SHOW_FLOW0(3, "");
if (device->node != NULL)
if (device->node != NULL) {
// device is registered
pnp->uninit_driver(device->node);
else
pnp->put_node(device->node);
} else {
// device is temporary
scsi_free_device(device);
}
release_sem(bus->scan_lun_lock);
}
@@ -563,8 +505,10 @@ scsi_device_interface scsi_device_module = {
NULL, // supported devices
NULL, // register node
scsi_init_device,
(status_t (*)(void *)) scsi_uninit_device,
(void (*)(device_node_handle, void *)) scsi_device_removed
(void (*)(void *)) scsi_uninit_device,
NULL, // register child devices
NULL, // rescan
(void (*)(void *)) scsi_device_removed
},
scsi_alloc_ccb,
@@ -71,7 +71,7 @@ scsi_init_emulation_buffer(scsi_device_info *device, size_t buffer_size)
// to satisfy alignment, we must allocate a buffer twice its required size
// and find the properly aligned part of it, ouch!
device->buffer_area = create_area("ATAPI buffer", (void *)&unaligned_addr, B_ANY_KERNEL_ADDRESS,
device->buffer_area = create_area("ATAPI buffer", (void *)&unaligned_addr, B_ANY_KERNEL_ADDRESS,
2 * total_size, B_CONTIGUOUS, 0);
if (device->buffer_area < 0) {
SHOW_ERROR( 1, "cannot create DMA buffer (%s)", strerror(device->buffer_area));
@@ -87,7 +87,7 @@ scsi_init_emulation_buffer(scsi_device_info *device, size_t buffer_size)
aligned_phys = (unaligned_phys + buffer_size - 1) & ~(buffer_size - 1);
aligned_addr = unaligned_addr + (aligned_phys - unaligned_phys);
SHOW_FLOW(3, "unaligned_phys = %#lx, aligned_phys = %#lx, unaligned_addr = %#lx, aligned_addr = %#lx",
SHOW_FLOW(3, "unaligned_phys = %#lx, aligned_phys = %#lx, unaligned_addr = %#lx, aligned_addr = %#lx",
unaligned_phys, aligned_phys, unaligned_addr, aligned_addr);
device->buffer = (void *)aligned_addr;
@@ -189,14 +189,14 @@ scsi_start_mode_select_6(scsi_ccb *request)
param_list_length_10 = param_list_length_6
- sizeof(scsi_mode_param_header_6) + sizeof(scsi_mode_param_header_10);
// we need to replace data header, thus use internal buffer
// we need to replace data header, thus use internal buffer
get_emulation_buffer(request);
// make sure our buffer is large enough
if (param_list_length_10 > device->buffer_size)
goto err;
// construct new cdb
// construct new cdb
request->cdb_length = sizeof(*cdb);
memset(cdb, 0, sizeof(*cdb));
@@ -210,7 +210,7 @@ scsi_start_mode_select_6(scsi_ccb *request)
cdb->control = cmd->control;
// copy and adapt header
// copy and adapt header
if (!copy_sg_data(request, 0, param_list_length_6, &header_6, sizeof(header_6), true))
goto err;
@@ -222,7 +222,7 @@ scsi_start_mode_select_6(scsi_ccb *request)
header_10->block_desc_length = B_HOST_TO_BENDIAN_INT16(
(uint16)header_6.block_desc_length);
// append actual mode select data
// append actual mode select data
if (!copy_sg_data(request, sizeof(header_6), param_list_length_6, header_10 + 1,
param_list_length_10 - sizeof(*header_10), true))
goto err;
@@ -289,7 +289,7 @@ scsi_finish_mode_sense_10_6(scsi_ccb *request)
// check how much data we got from device and thus will copy into
// request data
transfer_size_10 = request->data_length - request->data_resid;
transfer_size_6 = transfer_size_10
transfer_size_6 = transfer_size_10
- sizeof(scsi_mode_param_header_10 *) + sizeof(scsi_mode_param_header_6 *);
SHOW_FLOW(0, "fixing MODE SENSE(6) (%d bytes)", transfer_size_6);
@@ -309,11 +309,11 @@ scsi_finish_mode_sense_10_6(scsi_ccb *request)
header_6.dev_spec_parameter = header_10->dev_spec_parameter;
header_6.block_desc_length = B_BENDIAN_TO_HOST_INT16(header_10->block_desc_length);
// copy adapted header
// copy adapted header
copy_sg_data(request, 0, transfer_size_6, &header_6, sizeof(header_6), false);
// copy remaining data
copy_sg_data(request, sizeof(header_6), transfer_size_6,
copy_sg_data(request, sizeof(header_6), transfer_size_6,
header_10 + 1, transfer_size_10 - sizeof(*header_10), false);
request->data_resid = request->data_length - transfer_size_6;
@@ -439,7 +439,7 @@ copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
int sg_count = request->sg_count;
int req_size;
SHOW_FLOW(3, "offset=%u, req_size_limit=%d, size=%d, sg_list=%p, sg_count=%d, %s buffer",
SHOW_FLOW(3, "offset=%u, req_size_limit=%d, size=%d, sg_list=%p, sg_count=%d, %s buffer",
offset, allocation_length, size, sg_list, sg_count, to_buffer ? "to" : "from");
// skip unused S/G entries
@@ -452,7 +452,7 @@ copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
if (sg_count == 0)
return 0;
// remaining bytes we are allowed to copy from/to request
// remaining bytes we are allowed to copy from/to request
req_size = min(allocation_length, request->data_length) - offset;
// copy one S/G entry at a time
@@ -464,7 +464,7 @@ copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
bytes = min(bytes, sg_list->size);
if (vm_get_physical_page((addr_t)sg_list->address, (void *)&virtualAddress,
PHYSICAL_PAGE_CAN_WAIT) != B_OK)
PHYSICAL_PAGE_CAN_WAIT) != B_OK)
return false;
SHOW_FLOW(0, "buffer = %p, virt_addr = %#lx, bytes = %lu, to_buffer = %d",
@@ -475,30 +475,13 @@ copy_sg_data(scsi_ccb *request, uint offset, uint allocation_length,
else
memcpy((void *)(virtualAddress + offset), buffer, bytes);
#if 0
{
int i;
for (i = 0; i < bytes; ++i) {
char byte;
if (to_buffer)
byte = ((char *)virtualAddress)[offset + i];
else
byte = ((char *)buffer)[i];
FAST_LOG1( request->device->log, ev_copy_sg_data, byte );
}
}
#endif
vm_put_physical_page(virtualAddress);
buffer = (char *)buffer + bytes;
size -= bytes;
offset = 0;
}
return size == 0;
}
@@ -519,7 +502,7 @@ get_emulation_buffer(scsi_ccb *request)
request->sg_list = device->buffer_sg_list;
request->sg_count = device->buffer_sg_count;
request->data_length = device->buffer_size;
request->data_length = device->buffer_size;
}
@@ -539,7 +522,7 @@ replace_request_data(scsi_ccb *request)
request->sg_list = device->buffer_sg_list;
request->sg_count = device->buffer_sg_count;
request->data_length = device->buffer_size;
request->data_length = device->buffer_size;
}
+1 -7
View File
@@ -3,12 +3,6 @@
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI bus manager
Main file
*/
#include "scsi_internal.h"
#include <pnp_devfs.h>
@@ -25,6 +19,6 @@ module_info *modules[] = {
(module_info *)&scsi_for_sim_module,
(module_info *)&scsi_bus_module,
(module_info *)&scsi_device_module,
(module_info *)&scsi_bus_raw_module,
(module_info *)&gSCSIBusRawModule,
NULL
};
@@ -12,33 +12,14 @@
#include <scsi_cmds.h>
#include <locked_pool.h>
#include <device_manager.h>
#include <fast_log.h>
#define debug_level_error 2
#define debug_level_info 1
#define debug_level_flow 0
#define debug_level_error 4
#define debug_level_info 4
#define debug_level_flow 4
#define DEBUG_MSG_PREFIX "SCSI -- "
#include "wrapper.h"
//#define USE_FAST_LOG
#ifdef USE_FAST_LOG
#define FAST_LOG0( handle, event ) fast_log->log_0( handle, event )
#define FAST_LOG1( handle, event, param ) fast_log->log_1( handle, event, param )
#define FAST_LOG2( handle, event, param1, param2 ) fast_log->log_2( handle, event, param1, param2 )
#define FAST_LOG3( handle, event, param1, param2, param3 ) fast_log->log_3( handle, event, param1, param2, param3 )
#define FAST_LOGN( handle, event, num_params... ) fast_log->log_n( handle, event, num_params )
#else
#define FAST_LOG0( handle, event )
#define FAST_LOG1( handle, event, param )
#define FAST_LOG2( handle, event, param1, param2 )
#define FAST_LOG3( handle, event, param1, param2, param3 )
#define FAST_LOGN( handle, event, num_params... )
#endif
#include "scsi_lock.h"
@@ -50,7 +31,7 @@
// maximum number of fragments for temporary S/G lists
// for real SCSI controllers, there's no limit to transmission length
// but we need a limit - ATA transmits up to 128K, so we allow that
// (for massive data transmission, peripheral drivers should provide own
// (for massive data transmission, peripheral drivers should provide own
// SG list anyway)
// add one extra entry in case data is not page aligned
#define MAX_TEMP_SG_FRAGMENTS (128*1024 / B_PAGE_SIZE + 1)
@@ -64,7 +45,7 @@
// buffer size for emulated SCSI commands that ATAPI cannot handle;
// for MODE SELECT 6, maximum size is 255 + header,
// for MODE SENSE 6, we use MODE SENSE 10 which can return 64 K,
// but as the caller has to live with the 255 + header restriction,
// but as the caller has to live with the 255 + header restriction,
// we hope that this buffer is large enough
#define SCSI_ATAPI_BUFFER_SIZE 512
@@ -77,13 +58,13 @@
#define SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM "scsi/manual_autosense"
// name of internal scsi_bus_raw device driver
#define SCSI_BUS_RAW_MODULE_NAME "bus_managers/scsi/bus/raw"
#define SCSI_BUS_RAW_MODULE_NAME "bus_managers/scsi/bus/raw/device_v1"
// info about DPC
typedef struct scsi_dpc_info {
struct scsi_dpc_info *next;
bool registered; // true, if already/still in dpc list
void (*func)( void * );
void *arg;
} scsi_dpc_info;
@@ -99,43 +80,43 @@ typedef struct dma_params {
} dma_params;
// SCSI bus
// SCSI bus
typedef struct scsi_bus_info {
int lock_count; // sum of blocked[0..1] and sim_overflow
int blocked[2]; // depth of nested locks by bus manager (0) and SIM (1)
int left_slots; // left command queuing slots on HBA
bool sim_overflow; // 1, if SIM refused req because of bus queue overflow
uchar path_id; // SCSI path id
uint32 max_target_count; // maximum count of target_ids on the bus
thread_id service_thread; // service thread
sem_id start_service; // released whenever service thread has work to do
bool shutting_down; // set to true to tell service thread to shut down
benaphore mutex; // used to synchronize changes in queueing and blocking
sem_id scan_lun_lock; // allocated whenever a lun is scanned
scsi_sim_interface *interface; // SIM interface
scsi_sim_cookie sim_cookie; // internal SIM cookie
spinlock_irq dpc_lock; // synchronizer for dpc list
scsi_dpc_info *dpc_list; // list of dpcs to execute
struct scsi_device_info *waiting_devices; // devices ready to receive requests
locked_pool_cookie ccb_pool; // ccb pool (one per bus)
device_node_handle node; // pnp node of bus
device_node *node; // pnp node of bus
dma_params dma_params; // dma restrictions of controller
scsi_path_inquiry inquiry_data; // inquiry data as read on init
} scsi_bus_info;
// DMA buffer
// DMA buffer
typedef struct dma_buffer {
area_id area; // area of DMA buffer
uchar *address; // address of DMA buffer
@@ -161,7 +142,7 @@ typedef struct dma_buffer {
typedef struct scsi_device_info {
struct scsi_device_info *waiting_next;
struct scsi_device_info *waiting_prev;
bool manual_autosense : 1; // no autosense support
bool is_atapi : 1; // ATAPI device - needs some commands emulated
@@ -170,43 +151,38 @@ typedef struct scsi_device_info {
int sim_overflow; // 1, if SIM returned a request because of device queue overflow
int left_slots; // left command queuing slots for device
int total_slots; // total number of command queuing slots for device
scsi_ccb *queued_reqs; // queued requests, circularly doubly linked
// (scsi_insert_new_request depends on circular)
int64 last_sort; // last sort value (for elevator sort)
int32 valid; // access must be atomic!
scsi_bus_info *bus;
uchar target_id;
uchar target_lun;
scsi_ccb *auto_sense_request; // auto-sense request
scsi_ccb *auto_sense_originator; // request that auto-sense is
scsi_ccb *auto_sense_originator; // request that auto-sense is
// currently requested for
area_id auto_sense_area; // area of auto-sense data and S/G list
uint8 emulation_map[256/8]; // bit field with index being command code:
// 1 indicates that this command is not supported
// and thus must be emulated
scsi_res_inquiry inquiry_data;
device_node_handle node; // device node
device_node *node; // device node
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
char *buffer;
physical_entry *buffer_sg_list;
size_t buffer_sg_count;
size_t buffer_size;
size_t buffer_size;
area_id buffer_area;
sem_id buffer_sem;
} scsi_device_info;
@@ -240,12 +216,11 @@ enum {
extern locked_pool_interface *locked_pool;
extern device_manager_info *pnp;
extern fast_log_info *fast_log;
extern scsi_for_sim_interface scsi_for_sim_module;
extern scsi_bus_interface scsi_bus_module;
extern scsi_device_interface scsi_device_module;
extern struct pnp_devfs_driver_info scsi_bus_raw_module;
extern struct device_module_info gSCSIBusRawModule;
+23 -40
View File
@@ -22,8 +22,7 @@ scsi_requeue_request(scsi_ccb *request, bool bus_overflow)
scsi_bus_info *bus = request->bus;
scsi_device_info *device = request->device;
bool was_servicable, start_retry;
FAST_LOG1(device->log, ev_scsi_requeue_request, (uint32)request);
SHOW_FLOW0(3, "");
if (request->state != SCSI_STATE_SENT) {
@@ -56,15 +55,15 @@ scsi_requeue_request(scsi_ccb *request, bool bus_overflow)
} else {
// device has overflown
scsi_set_device_overflow(device);
scsi_remove_device_queue(device);
// either, the device has refused the request, i.e. it was transmitted
scsi_remove_device_queue(device);
// either, the device has refused the request, i.e. it was transmitted
// over the bus - in this case, the bus cannot be overloaded anymore;
// or, the driver detected that the device can not be able to process
// further requests, because the driver knows its maximum queue depth
// or something - in this case, the bus state hasn't changed, but the
// driver will tell us about any overflow when we submit the next
// further requests, because the driver knows its maximum queue depth
// or something - in this case, the bus state hasn't changed, but the
// driver will tell us about any overflow when we submit the next
// request, so the overflow state will be fixed automatically
scsi_clear_bus_overflow(bus);
scsi_clear_bus_overflow(bus);
}
start_retry = !was_servicable && scsi_can_service_bus(bus);
@@ -86,7 +85,6 @@ scsi_resubmit_request(scsi_ccb *request)
scsi_device_info *device = request->device;
bool was_servicable, start_retry;
FAST_LOG1(device->log, ev_scsi_resubmit_request, (uint32)request);
SHOW_FLOW0(3, "");
if (request->state != SCSI_STATE_SENT) {
@@ -119,7 +117,7 @@ scsi_resubmit_request(scsi_ccb *request)
// if device is not blocked (anymore) add it to waiting list of bus
if (device->lock_count == 0) {
scsi_add_device_queue_first(device);
// as previous line does nothing if already queued, we force device
// as previous line does nothing if already queued, we force device
// to be the next one to get handled
bus->waiting_devices = device;
}
@@ -141,7 +139,6 @@ submit_autosense(scsi_ccb *request)
{
scsi_device_info *device = request->device;
FAST_LOG1(device->log, ev_scsi_submit_autosense, (uint32)request);
//snooze(1000000);
SHOW_FLOW0(3, "sending autosense");
@@ -174,14 +171,13 @@ finish_autosense(scsi_device_info *device)
scsi_ccb *orig_request = device->auto_sense_originator;
scsi_ccb *request = device->auto_sense_request;
FAST_LOG2(device->log, ev_scsi_finish_autosense, (uint32)request, (uint32)orig_request);
SHOW_FLOW0(3, "");
if (request->subsys_status == SCSI_REQ_CMP) {
int sense_len;
// we got sense data -> copy it to sense buffer
sense_len = min(SCSI_MAX_SENSE_SIZE,
sense_len = min(SCSI_MAX_SENSE_SIZE,
request->data_length - request->data_resid);
SHOW_FLOW(3, "Got sense: %d bytes", sense_len);
@@ -209,8 +205,6 @@ scsi_device_queue_overflow(scsi_ccb *request, uint num_requests)
scsi_device_info *device = request->device;
int diff_max_slots;
FAST_LOG2(device->log, ev_scsi_device_queue_overflow, (uint32)request, num_requests);
// set maximum number of concurrent requests to number of
// requests running when QUEUE FULL condition occurred - 1
// (the "1" is the refused request)
@@ -222,7 +216,7 @@ scsi_device_queue_overflow(scsi_ccb *request, uint num_requests)
SHOW_INFO(2, "Restricting device queue to %d requests", num_requests);
// update slot count
// update slot count
ACQUIRE_BEN(&bus->mutex);
diff_max_slots = device->total_slots - num_requests;
@@ -245,7 +239,6 @@ scsi_request_finished(scsi_ccb *request, uint num_requests)
scsi_bus_info *bus = request->bus;
bool was_servicable, start_service, do_autosense;
FAST_LOG2(device->log, ev_scsi_request_finished, (uint32)request, num_requests);
SHOW_FLOW(3, "%p", request);
if (request->state != SCSI_STATE_SENT) {
@@ -272,9 +265,9 @@ scsi_request_finished(scsi_ccb *request, uint num_requests)
was_servicable = scsi_can_service_bus(bus);
// do pseudo-autosense if device doesn't support it and
// device reported a check condition state and auto-sense haven't
// been retrieved by SIM
// do pseudo-autosense if device doesn't support it and
// device reported a check condition state and auto-sense haven't
// been retrieved by SIM
// (last test is implicit as SIM adds SCSI_AUTOSNS_VALID to subsys_status)
do_autosense = device->manual_autosense
&& (request->flags & SCSI_DIS_AUTOSENSE) == 0
@@ -303,7 +296,7 @@ scsi_request_finished(scsi_ccb *request, uint num_requests)
scsi_clear_device_overflow(device);
scsi_clear_bus_overflow(bus);
// if device is not blocked (anymore) and has pending requests,
// if device is not blocked (anymore) and has pending requests,
// add it to waiting list of bus
if (device->lock_count == 0 && device->queued_reqs != NULL)
scsi_add_device_queue_last(device);
@@ -358,13 +351,13 @@ scsi_check_enqueue_request(scsi_ccb *request)
scsi_add_queued_request(request);
execute = false;
} else {
// if bus is saturated, block it
// if bus is saturated, block it
if (--bus->left_slots == 0) {
SHOW_FLOW0(3, "bus is saturated, blocking further requests");
scsi_block_bus_nolock(bus, false);
}
// if device saturated or blocking request, block device
// if device saturated or blocking request, block device
if (--device->left_slots == 0 || request->ordered) {
SHOW_FLOW0( 3, "device is saturated/blocked by requests, blocking further requests" );
scsi_block_device_nolock(device, false);
@@ -379,7 +372,7 @@ scsi_check_enqueue_request(scsi_ccb *request)
}
RELEASE_BEN(&bus->mutex);
return execute;
}
@@ -398,7 +391,7 @@ scsi_async_io(scsi_ccb *request)
scsi_bus_info *bus = request->bus;
//SHOW_FLOW( 0, "path_id=%d", bus->path_id );
//snooze( 1000000 );
// do some sanity tests first
@@ -413,14 +406,6 @@ scsi_async_io(scsi_ccb *request)
goto err;
}
FAST_LOGN(request->device->log, ev_scsi_async_io,
func_group_len[request->cdb[0] >> 5] + 2,
(uint32)request, request->data_length,
request->cdb[0], request->cdb[1], request->cdb[2], request->cdb[3],
request->cdb[4], request->cdb[5], request->cdb[6], request->cdb[7],
request->cdb[8], request->cdb[9], request->cdb[10], request->cdb[11],
request->cdb[12], request->cdb[13], request->cdb[14], request->cdb[15]);
if (!request->device->valid) {
SHOW_ERROR0( 3, "device got removed" );
@@ -483,7 +468,7 @@ scsi_async_io(scsi_ccb *request)
// give SIM a well-defined first state
request->sim_state = 0;
// make sure device/bus is not blocked
// make sure device/bus is not blocked
if (!scsi_check_enqueue_request(request))
return;
@@ -572,7 +557,7 @@ scsi_abort(scsi_ccb *req_to_abort)
req_to_abort->subsys_status = SCSI_REQ_ABORTED;
// finish emulation
// finish emulation
if (req_to_abort->emulated)
scsi_finish_emulation(req_to_abort);
@@ -617,13 +602,13 @@ scsi_check_exec_service(scsi_bus_info *bus)
request = device->queued_reqs;
scsi_remove_queued_request(request);
// if bus is saturated, block it
// if bus is saturated, block it
if (--bus->left_slots == 0) {
SHOW_FLOW0(3, "bus is saturated, blocking further requests");
scsi_block_bus_nolock(bus, false);
}
// if device saturated or blocking request, block device
// if device saturated or blocking request, block device
if (--device->left_slots == 0 || request->ordered) {
SHOW_FLOW0(3, "device is saturated/blocked by requests, blocking further requests");
scsi_block_device_nolock(device, false);
@@ -636,13 +621,11 @@ scsi_check_exec_service(scsi_bus_info *bus)
RELEASE_BEN(&bus->mutex);
FAST_LOG1(request->device->log, ev_scsi_do_resend_request, (uint32)request);
request->state = SCSI_STATE_SENT;
bus->interface->scsi_io(bus->sim_cookie, request);
return true;
}
}
RELEASE_BEN(&bus->mutex);
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2006, Haiku, Inc. All RightsReserved.
* Copyright 2004-2008, Haiku, Inc. All RightsReserved.
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
@@ -13,75 +13,91 @@
#include "scsi_internal.h"
#include "queuing.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/** new scsi controller added
* in return, we register a new scsi bus node and let its fixed
* in return, we register a new scsi bus node and let its fixed
* consumer (the SCSI device layer) automatically scan it for devices
*/
static status_t
scsi_controller_added(device_node_handle parent)
scsi_controller_added(device_node *parent)
{
char *controller_name;
int path_id;
const char *controller_name;
int pathID;
SHOW_FLOW0(4, "");
if (pnp->get_attr_string(parent, SCSI_DESCRIPTION_CONTROLLER_NAME,
&controller_name, false) != B_OK) {
if (pnp->get_attr_string(parent, SCSI_DESCRIPTION_CONTROLLER_NAME,
&controller_name, false) != B_OK) {
dprintf("scsi: ignored controller - controller name missing\n");
return B_ERROR;
}
path_id = pnp->create_id(SCSI_PATHID_GENERATOR);
if (path_id < 0) {
pathID = pnp->create_id(SCSI_PATHID_GENERATOR);
if (pathID < 0) {
dprintf("scsi: Cannot register SCSI controller %s - out of path IDs\n",
controller_name);
free(controller_name);
return B_ERROR;
}
free(controller_name);
{
device_attr attrs[] = {
// general information
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_BUS_MODULE_NAME }},
// we are a bus
{ PNP_BUS_IS_BUS, B_UINT8_TYPE, { ui8: 1 }},
// remember who we are
// remember who we are
// (could use the controller name, but probably some software would choke)
{ SCSI_BUS_PATH_ID_ITEM, B_UINT8_TYPE, { ui8: path_id }},
{ SCSI_BUS_PATH_ID_ITEM, B_UINT8_TYPE, { ui8: pathID }},
// tell PnP manager to clean up ID
{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: SCSI_PATHID_GENERATOR }},
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }},
// tell internal bus raw driver to register bus' device in devfs
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: SCSI_BUS_RAW_MODULE_NAME }},
{ NULL, 0 }
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: SCSI_PATHID_GENERATOR }},
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }},
{}
};
device_node_handle node;
return pnp->register_node(parent, SCSI_BUS_MODULE_NAME, attrs, NULL,
NULL);
}
}
static status_t
scsi_controller_init(device_node *node, void **_cookie)
{
*_cookie = node;
return B_OK;
}
static status_t
scsi_controller_register_raw_device(void *_cookie)
{
device_node *node = (device_node *)_cookie;
uint32 channel;
uint8 pathID;
char *name;
#if 1
// TODO: this seems to cause a crash in some configurations, and needs to be investigated!
// see bug #389 and #393.
#if 0
uint32 channel;
if (pnp->get_attr_uint32(parent, "ide/channel_id", &channel, true) == B_OK) {
// this is actually an IDE device, we don't need to publish
// a bus device for those
attrs[5].name = NULL;
}
#endif
return pnp->register_device(parent, attrs, NULL, &node);
// TODO: check if the above is still true
if (pnp->get_attr_uint32(node, "ide/channel_id", &channel, true) == B_OK) {
// this is actually an IDE device, we don't need to publish
// a bus device for those
return B_OK;
}
#endif
pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &pathID, false);
// put that on heap to not overflow the limited kernel stack
name = malloc(PATH_MAX + 1);
if (name == NULL)
return B_NO_MEMORY;
snprintf(name, PATH_MAX + 1, "bus/scsi/%d/bus_raw", pathID);
return pnp->publish_device(node, name, SCSI_BUS_RAW_MODULE_NAME);
}
@@ -110,9 +126,11 @@ scsi_for_sim_interface scsi_for_sim_module =
NULL, // supported devices
scsi_controller_added,
NULL,
NULL,
NULL
scsi_controller_init,
NULL, // uninit
scsi_controller_register_raw_device,
NULL, // rescan
NULL, // removed
},
scsi_requeue_request,
@@ -17,7 +17,7 @@
#ifdef DEBUG_WAIT_ON_MSG
# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG );
#else
# define DEBUG_WAIT
# define DEBUG_WAIT
#endif
#ifdef DEBUG_WAIT_ON_ERROR
@@ -43,7 +43,7 @@
#endif
#ifndef debug_level_flow
# define debug_level_flow 3
# define debug_level_flow 4
#endif
#ifndef debug_level_info
@@ -23,7 +23,7 @@
#include "wrapper.h"
#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/device_v1"
#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/driver_v1"
#define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1"
#define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller"
@@ -33,6 +33,13 @@ static ide_adapter_interface *ide_adapter;
device_manager_info *pnp;
static void
set_channel(void *cookie, ide_channel channel)
{
ide_adapter->set_channel((ide_adapter_channel_info *)cookie, channel);
}
static status_t
write_command_block_regs(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
{
@@ -76,7 +83,7 @@ read_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit)
static status_t
prepare_dma(void *channel_cookie,
prepare_dma(void *channel_cookie,
const physical_entry *sg_list, size_t sg_list_count,
bool to_device)
{
@@ -99,58 +106,56 @@ finish_dma(void *channel_cookie)
static status_t
init_channel(device_node_handle node, ide_channel ide_channel,
void **channel_cookie)
init_channel(device_node *node, void **channel_cookie)
{
return ide_adapter->init_channel(node, ide_channel,
(ide_adapter_channel_info **)channel_cookie,
return ide_adapter->init_channel(node,
(ide_adapter_channel_info **)channel_cookie,
sizeof(ide_adapter_channel_info), ide_adapter->inthand);
}
static status_t
static void
uninit_channel(void *channel_cookie)
{
return ide_adapter->uninit_channel((ide_adapter_channel_info *)channel_cookie);
ide_adapter->uninit_channel((ide_adapter_channel_info *)channel_cookie);
}
static void
channel_removed(device_node_handle node, void *channel_cookie)
channel_removed(void *channel_cookie)
{
return ide_adapter->channel_removed(node, (ide_adapter_channel_info *)channel_cookie);
ide_adapter->channel_removed((ide_adapter_channel_info *)channel_cookie);
}
static status_t
init_controller(device_node_handle node, void *user_cookie,
ide_adapter_controller_info **cookie)
init_controller(device_node *node, ide_adapter_controller_info **cookie)
{
return ide_adapter->init_controller(node, user_cookie, cookie,
return ide_adapter->init_controller(node, cookie,
sizeof( ide_adapter_controller_info));
}
static status_t
static void
uninit_controller(ide_adapter_controller_info *controller)
{
return ide_adapter->uninit_controller(controller);
ide_adapter->uninit_controller(controller);
}
static void
controller_removed(device_node_handle node, ide_adapter_controller_info *controller)
controller_removed(ide_adapter_controller_info *controller)
{
return ide_adapter->controller_removed(node, controller);
return ide_adapter->controller_removed(controller);
}
static status_t
probe_controller(device_node_handle parent)
probe_controller(device_node *parent)
{
return ide_adapter->probe_controller(parent,
GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME, "generic_ide_pci",
"Generic IDE PCI Controller",
"Generic IDE PCI Controller",
GENERIC_IDE_PCI_CHANNEL_MODULE_NAME,
true,
true, // assume that command queuing works
@@ -162,35 +167,22 @@ probe_controller(device_node_handle parent)
static float
supports_device(device_node_handle parent, bool *_noConnection)
supports_device(device_node *parent)
{
char *bus;
uint8 baseClass, subClass;
const char *bus;
uint16 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 (pnp->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
|| pnp->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass, false) != B_OK
|| pnp->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass, false) != B_OK)
return -1;
if (strcmp(bus, "pci") || baseClass != PCI_mass_storage || subClass != PCI_ide) {
free(bus);
return 0.0;
}
if (strcmp(bus, "pci") || baseClass != PCI_mass_storage
|| subClass != PCI_ide)
return 0.0f;
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;
return 0.3f;
}
@@ -227,13 +219,15 @@ static ide_controller_interface channel_interface = {
NULL, // supports device
NULL, // register device
(status_t (*)(device_node_handle, void *, void **))init_channel,
(status_t (*)(device_node *, void **))init_channel,
uninit_channel,
NULL, // register child devices
NULL, // rescan
channel_removed,
NULL, // cleanup
NULL, // get_paths
},
&set_channel,
&write_command_block_regs,
&read_command_block_regs,
@@ -258,11 +252,11 @@ static driver_module_info controller_interface = {
supports_device,
probe_controller,
(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,
(status_t (*)(device_node *, void **)) init_controller,
(void (*)(void *)) uninit_controller,
NULL, // register child devices
NULL, // rescan
(void (*)(void *)) controller_removed,
};
module_info *modules[] = {
+67 -122
View File
@@ -131,7 +131,7 @@ get_device_info(uint16 vendorID, uint16 deviceID, const char **name,
static status_t
register_sim(device_node_handle parent)
register_sim(device_node *parent)
{
int32 id = gDeviceManager->create_id(AHCI_ID_GENERATOR);
if (id < 0)
@@ -139,25 +139,22 @@ register_sim(device_node_handle parent)
{
device_attr attrs[] = {
{ B_DRIVER_MODULE, B_STRING_TYPE,
{ string: AHCI_SIM_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE,
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
{ string: SCSI_FOR_SIM_MODULE_NAME }},
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE,
{ string: AHCI_DEVICE_MODULE_NAME }},
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: 255 }},
{ AHCI_ID_ITEM, B_UINT32_TYPE, { ui32: id }},
{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
{ string: AHCI_ID_GENERATOR }},
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: id }},
// { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE,
// { string: AHCI_ID_GENERATOR }},
// { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: id }},
{ NULL }
};
device_node_handle node;
status_t status = gDeviceManager->register_device(parent, attrs, NULL,
&node);
status_t status = gDeviceManager->register_node(parent,
AHCI_SIM_MODULE_NAME, attrs, NULL, NULL);
if (status < B_OK)
gDeviceManager->free_id(AHCI_ID_GENERATOR, id);
@@ -170,33 +167,38 @@ register_sim(device_node_handle parent)
static float
ahci_supports_device(device_node_handle parent, bool *_noConnection)
ahci_supports_device(device_node *parent)
{
uint8 baseClass, subClass, classAPI;
uint16 baseClass, subClass, classAPI;
uint16 vendorID;
uint16 deviceID;
bool isPCI;
const char *name;
char *bus;
const char *bus;
TRACE("ahci_supports_device\n");
if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false) < B_OK)
return 0.0f;
isPCI = !strcmp(bus, "pci");
free(bus);
if (!isPCI)
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
< B_OK)
return 0.0f;
if (gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_BASE_CLASS_ID_ITEM, &baseClass, false) < B_OK
|| gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_SUB_CLASS_ID_ITEM, &subClass, false) < B_OK
|| gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_API_ID_ITEM, &classAPI, false) < B_OK
|| gDeviceManager->get_attr_uint16(parent, PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, false) < B_OK
|| gDeviceManager->get_attr_uint16(parent, PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, false) < B_OK)
if (strcmp(bus, "pci"))
return 0.0f;
if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass,
false) < B_OK
|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass,
false) < B_OK
|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_INTERFACE,
&classAPI, false) < B_OK
|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
&vendorID, false) < B_OK
|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
false) < B_OK)
return 0.0f;
if (get_device_info(vendorID, deviceID, &name, NULL) < B_OK) {
if (baseClass != PCI_mass_storage || subClass != PCI_sata || classAPI != PCI_sata_ahci)
if (baseClass != PCI_mass_storage || subClass != PCI_sata
|| classAPI != PCI_sata_ahci)
return 0.0f;
TRACE("generic AHCI controller found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID);
return 0.8f;
@@ -205,23 +207,15 @@ ahci_supports_device(device_node_handle parent, bool *_noConnection)
if (vendorID == PCI_VENDOR_JMICRON) {
// JMicron uses the same device ID for SATA and PATA controllers,
// check if BAR5 exists to determine if it's a AHCI controller
uint8 bus, device, function;
pci_device_module_info *pci;
pci_device *device;
pci_info info;
pci_module_info *pci;
size_t size = 0;
int i;
gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_BUS_ITEM, &bus, false);
gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_DEVICE_ITEM, &device, false);
gDeviceManager->get_attr_uint8(parent, PCI_DEVICE_FUNCTION_ITEM, &function, false);
get_module(B_PCI_MODULE_NAME, (module_info **)&pci);
for (i = 0; B_OK == pci->get_nth_pci_info(i, &info); i++) {
if (info.bus == bus && info.device == device && info.function == function) {
size = info.u.h0.base_register_sizes[5];
break;
}
}
put_module(B_PCI_MODULE_NAME);
if (size == 0)
gDeviceManager->get_driver(parent, (driver_module_info **)&pci,
(void **)&device);
pci->get_pci_info(device, &info);
if (info.u.h0.base_register_sizes[5] == 0)
return 0.0f;
}
@@ -231,20 +225,14 @@ ahci_supports_device(device_node_handle parent, bool *_noConnection)
static status_t
ahci_register_device(device_node_handle parent)
ahci_register_device(device_node *parent)
{
device_node_handle node;
status_t status;
device_attr attrs[] = {
// info about ourself and our consumer
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: AHCI_DEVICE_MODULE_NAME }},
{ SCSI_DEVICE_MAX_TARGET_COUNT, B_UINT32_TYPE,
{ ui32: 33 }},
// DMA properties
// data must be word-aligned;
// data must be word-aligned;
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE,
{ ui32: 1 }},
// one S/G block must not cross 64K boundary
@@ -261,86 +249,44 @@ ahci_register_device(device_node_handle parent)
TRACE("ahci_register_device\n");
status = gDeviceManager->register_device(parent, attrs,
NULL, &node);
if (status < B_OK)
return status;
return gDeviceManager->register_node(parent, AHCI_DEVICE_MODULE_NAME,
attrs, NULL, NULL);
}
static status_t
ahci_init_driver(device_node *node, void **_cookie)
{
TRACE("ahci_init_driver\n");
*_cookie = node;
return B_OK;
}
static void
ahci_uninit_driver(void *cookie)
{
TRACE("ahci_uninit_driver, cookie %p\n", cookie);
}
static status_t
ahci_register_child_devices(void *cookie)
{
device_node *node = (device_node *)cookie;
// TODO: register SIM for every controller we find!
return register_sim(node);
}
static status_t
ahci_init_driver(device_node_handle node, void *userCookie, void **_cookie)
{
pci_device *_userCookie = userCookie;
pci_device pciDevice;
device_node_handle parent;
status_t status;
TRACE("ahci_init_driver, userCookie %p\n", userCookie);
parent = gDeviceManager->get_parent(node);
// initialize parent (the bus) to get the PCI interface and device
status = gDeviceManager->init_driver(parent, NULL,
(driver_module_info **)&gPCI, (void **)&pciDevice);
if (status != B_OK)
return status;
TRACE("ahci_init_driver: gPCI %p, pciDevice %p\n", gPCI, pciDevice);
gDeviceManager->put_device_node(parent);
*_userCookie = pciDevice;
*_cookie = node;
return B_OK;
}
static status_t
ahci_uninit_driver(void *cookie)
{
device_node_handle node = cookie;
device_node_handle parent;
TRACE("ahci_uninit_driver, cookie %p\n", cookie);
parent = gDeviceManager->get_parent(node);
gDeviceManager->uninit_driver(parent);
gDeviceManager->put_device_node(parent);
return B_OK;
}
static void
ahci_device_removed(device_node_handle node, void *cookie)
ahci_device_removed(void *cookie)
{
TRACE("ahci_device_removed, cookie %p\n", cookie);
}
static void
ahci_device_cleanup(device_node_handle node)
{
TRACE("ahci_device_cleanup\n");
}
static void
ahci_get_supported_paths(const char ***_busses, const char ***_devices)
{
static const char *kBus[] = { "pci", NULL };
static const char *kDevice[] = { "drivers/dev/disk/sata", NULL };
TRACE("ahci_get_supported_paths\n");
*_busses = kBus;
*_devices = kDevice;
}
static status_t
std_ops(int32 op, ...)
{
@@ -365,15 +311,14 @@ driver_module_info sAHCIDevice = {
ahci_register_device,
ahci_init_driver,
ahci_uninit_driver,
ahci_device_removed,
ahci_device_cleanup,
ahci_get_supported_paths,
ahci_register_child_devices,
NULL, // rescan
ahci_device_removed
};
module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
// { B_PCI_MODULE_NAME, (module_info **)&gPCI },
{ SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI },
{}
};
@@ -15,7 +15,7 @@
#define FLOW(a...) dprintf("ahci: " a)
AHCIController::AHCIController(device_node_handle node, pci_device_info *device)
AHCIController::AHCIController(device_node *node, pci_device *device)
: fNode(node)
, fPCIDevice(device)
, fPCIVendorID(0xffff)
@@ -48,23 +48,19 @@ status_t
AHCIController::Init()
{
pci_info pciInfo;
if (gPCI->get_pci_info(fPCIDevice, &pciInfo) < B_OK) {
dprintf("AHCIController::Init ERROR: getting PCI info failed!\n");
return B_ERROR;
}
gPCI->get_pci_info(fPCIDevice, &pciInfo);
fPCIVendorID = pciInfo.vendor_id;
fPCIDeviceID = pciInfo.device_id;
TRACE("AHCIController::Init %u:%u:%u vendor %04x, device %04x\n",
TRACE("AHCIController::Init %u:%u:%u vendor %04x, device %04x\n",
pciInfo.bus, pciInfo.device, pciInfo.function, fPCIVendorID, fPCIDeviceID);
// --- Instance check workaround begin
char sName[32];
snprintf(sName, sizeof(sName), "ahci-inst-%u-%u-%u", pciInfo.bus, pciInfo.device, pciInfo.function);
if (find_port(sName) >= 0) {
dprintf("AHCIController::Init ERROR: an instance for object %u:%u:%u already exists\n",
dprintf("AHCIController::Init ERROR: an instance for object %u:%u:%u already exists\n",
pciInfo.bus, pciInfo.device, pciInfo.function);
return B_ERROR;
}
@@ -231,7 +227,6 @@ AHCIController::Uninit()
// well...
remove_io_interrupt_handler(fIRQ, Interrupt, this);
delete_area(fRegsArea);
// --- Instance check workaround begin
@@ -245,7 +240,7 @@ AHCIController::ResetController()
{
uint32 saveCaps = fRegs->cap & (CAP_SMPS | CAP_SSS | CAP_SPM | CAP_EMS | CAP_SXS);
uint32 savePI = fRegs->pi;
fRegs->ghc |= GHC_HR;
FlushPostedWrites();
if (wait_until_clear(&fRegs->ghc, GHC_HR, 1000000) < B_OK)
@@ -12,45 +12,44 @@
class AHCIController {
public:
AHCIController(device_node_handle node,
pci_device_info *pciDevice);
~AHCIController();
AHCIController(device_node *node, pci_device *pciDevice);
~AHCIController();
status_t Init();
void Uninit();
status_t Init();
void Uninit();
void ExecuteRequest(scsi_ccb *request);
uchar AbortRequest(scsi_ccb *request);
uchar TerminateRequest(scsi_ccb *request);
uchar ResetDevice(uchar targetID, uchar targetLUN);
void GetRestrictions(uchar targetID, bool *isATAPI, bool *noAutoSense, uint32 *maxBlocks);
void ExecuteRequest(scsi_ccb *request);
uchar AbortRequest(scsi_ccb *request);
uchar TerminateRequest(scsi_ccb *request);
uchar ResetDevice(uchar targetID, uchar targetLUN);
void GetRestrictions(uchar targetID, bool *isATAPI, bool *noAutoSense, uint32 *maxBlocks);
device_node_handle DeviceNode() { return fNode; }
device_node * DeviceNode() { return fNode; }
private:
bool IsDevicePresent(uint device);
status_t ResetController();
void FlushPostedWrites();
bool IsDevicePresent(uint device);
status_t ResetController();
void FlushPostedWrites();
static int32 Interrupt(void *data);
static int32 Interrupt(void *data);
friend class AHCIPort;
private:
device_node_handle fNode;
pci_device_info* fPCIDevice;
uint16 fPCIVendorID;
uint16 fPCIDeviceID;
uint32 fFlags;
device_node * fNode;
pci_device * fPCIDevice;
uint16 fPCIVendorID;
uint16 fPCIDeviceID;
uint32 fFlags;
volatile ahci_hba * fRegs;
area_id fRegsArea;
int fCommandSlotCount;
int fPortCountMax;
int fPortCountAvail;
uint32 fPortImplementedMask;
uint8 fIRQ;
AHCIPort * fPort[32];
volatile ahci_hba * fRegs;
area_id fRegsArea;
int fCommandSlotCount;
int fPortCountMax;
int fPortCountAvail;
uint32 fPortImplementedMask;
uint8 fIRQ;
AHCIPort * fPort[32];
// --- Instance check workaround begin
port_id fInstanceCheck;
@@ -22,11 +22,17 @@ scsi_for_sim_interface *gSCSI;
// #pragma mark - SIM module interface
static void
ahci_set_scsi_bus(scsi_sim_cookie cookie, scsi_bus bus)
{
}
//! execute request
static void
ahci_scsi_io(scsi_sim_cookie cookie, scsi_ccb *request)
{
FLOW("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n",
FLOW("ahci_scsi_io, cookie %p, path_id %u, target_id %u, target_lun %u\n",
cookie, request->path_id, request->target_id, request->target_lun);
static_cast<AHCIController *>(cookie)->ExecuteRequest(request);
}
@@ -96,7 +102,7 @@ ahci_reset_bus(scsi_sim_cookie cookie)
}
/*! Get restrictions of one device
/*! Get restrictions of one device
(used for non-SCSI transport protocols and bug fixes)
*/
static void
@@ -122,30 +128,26 @@ ahci_ioctl(scsi_sim_cookie cookie, uint8 targetID, uint32 op, void *buffer,
static status_t
ahci_sim_init_bus(device_node_handle node, void *userCookie, void **_cookie)
ahci_sim_init_bus(device_node *node, void **_cookie)
{
pci_device_info *pciDevice;
device_node_handle parent;
AHCIController *controller;
status_t status;
TRACE("ahci_sim_init_bus\n");
TRACE("ahci_sim_init_bus: userCookie %p\n", userCookie);
// get the PCI device from our parent's parent
device_node *parent = gDeviceManager->get_parent_node(node);
device_node *pciParent = gDeviceManager->get_parent_node(parent);
gDeviceManager->put_node(parent);
TRACE("ahci_sim_init_bus: gPCI %p\n", gPCI);
// initialize parent (the bus) to get the PCI device
parent = gDeviceManager->get_parent(node);
status = gDeviceManager->init_driver(parent, &pciDevice, NULL, NULL);
gDeviceManager->put_device_node(parent);
if (status != B_OK)
return status;
pci_device *pciDevice;
gDeviceManager->get_driver(pciParent, NULL, (void **)&pciDevice);
gDeviceManager->put_node(pciParent);
TRACE("ahci_sim_init_bus: pciDevice %p\n", pciDevice);
controller = new(std::nothrow) AHCIController(node, pciDevice);
AHCIController *controller = new(std::nothrow) AHCIController(node,
pciDevice);
if (!controller)
return B_NO_MEMORY;
status = controller->Init();
status_t status = controller->Init();
if (status < B_OK) {
delete controller;
return status;
@@ -157,27 +159,19 @@ ahci_sim_init_bus(device_node_handle node, void *userCookie, void **_cookie)
}
static status_t
static void
ahci_sim_uninit_bus(void *cookie)
{
TRACE("ahci_sim_uninit_bus, cookie %p\n", cookie);
AHCIController *controller = static_cast<AHCIController *>(cookie);
device_node_handle parent = gDeviceManager->get_parent(
controller->DeviceNode());
controller->Uninit();
delete controller;
gDeviceManager->uninit_driver(parent);
gDeviceManager->put_device_node(parent);
return B_OK;
}
static void
ahci_sim_bus_removed(device_node_handle node, void *cookie)
ahci_sim_bus_removed(void *cookie)
{
TRACE("ahci_sim_bus_removed, cookie %p\n", cookie);
}
@@ -204,14 +198,15 @@ scsi_sim_interface gAHCISimInterface = {
0,
std_ops
},
NULL, // supported devices
NULL, // supported devices
NULL, // register node
ahci_sim_init_bus,
ahci_sim_uninit_bus,
ahci_sim_bus_removed,
NULL, // device cleanup
NULL, // get supported paths
NULL, // register child devices
NULL, // rescan
ahci_sim_bus_removed
},
ahci_set_scsi_bus,
ahci_scsi_io,
ahci_abort_io,
ahci_reset_device,
@@ -222,4 +217,3 @@ scsi_sim_interface gAHCISimInterface = {
ahci_get_restrictions,
ahci_ioctl
};
@@ -17,75 +17,57 @@
status_t
das_init_device(device_node_handle node, void *user_cookie, void **cookie)
das_init_device(device_node *node, void **cookie)
{
das_device_info *device;
status_t res;
scsi_ccb *request;
status_t status;
uint8 removable;
SHOW_FLOW0(3, "");
status = pnp->get_attr_uint8(node, "removable",
&removable, false);
if (status != B_OK)
return status;
device = (das_device_info *)malloc(sizeof(*device));
if (device == NULL)
return B_NO_MEMORY;
memset(device, 0, sizeof(*device));
device->block_io_device = user_cookie;
device->node = node;
device->removable = removable;
res = pnp->get_attr_uint8(node, "removable",
&device->removable, false);
if (res != B_OK)
goto err1;
// register it everywhere
res = pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&device->scsi,
(void **)&device->scsi_device);
if (res != B_OK)
goto err2;
res = scsi_periph->register_device((periph_device_cookie)device, &callbacks,
device->scsi_device, device->scsi, device->node, device->removable,
&device->scsi_periph_device);
if (res != B_OK)
goto err3;
// and get (initial) capacity
request = device->scsi->alloc_ccb(device->scsi_device);
if (request == NULL) {
res = B_NO_MEMORY;
goto err4;
{
device_node *parent = pnp->get_parent_node(node);
pnp->get_driver(parent, (driver_module_info **)&device->scsi,
(void **)&device->scsi_device);
pnp->put_node(parent);
}
scsi_periph->check_capacity(device->scsi_periph_device, request);
device->scsi->free_ccb(request);
status = scsi_periph->register_device((periph_device_cookie)device,
&callbacks, device->scsi_device, device->scsi, device->node,
device->removable, &device->scsi_periph_device);
if (status != B_OK) {
free(device);
return status;
}
SHOW_FLOW0(3, "done");
*cookie = device;
return B_OK;
err4:
scsi_periph->unregister_device(device->scsi_periph_device);
err3:
pnp->uninit_driver(pnp->get_parent(node));
err2:
err1:
free(device);
return res;
}
status_t
das_uninit_device(das_device_info *device)
void
das_uninit_device(void *_cookie)
{
scsi_periph->unregister_device(device->scsi_periph_device);
pnp->uninit_driver(pnp->get_parent(device->node));
free(device);
das_device_info *device = (das_device_info *)_cookie;
return B_OK;
scsi_periph->unregister_device(device->scsi_periph_device);
free(device);
}
@@ -95,51 +77,39 @@ das_uninit_device(das_device_info *device)
*/
status_t
das_device_added(device_node_handle node)
das_device_added(device_node *node)
{
scsi_res_inquiry *device_inquiry = NULL;
const scsi_res_inquiry *deviceInquiry = NULL;
uint8 device_type;
size_t inquiry_len;
char *name;
size_t inquiryLength;
uint32 max_blocks;
// 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)
goto err;
return B_ERROR;
// get inquiry data
if (pnp->get_attr_raw(node, SCSI_DEVICE_INQUIRY_ITEM,
(void **)&device_inquiry, &inquiry_len, true) != B_OK
|| inquiry_len < sizeof(device_inquiry))
goto err;
(const void **)&deviceInquiry, &inquiryLength, true) != B_OK
|| inquiryLength < sizeof(deviceInquiry))
return B_ERROR;
// get block limit of underlying hardware to lower it (if necessary)
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &max_blocks, true) != B_OK)
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &max_blocks,
true) != B_OK)
max_blocks = INT_MAX;
// using 10 byte commands, at most 0xffff blocks can be transmitted at once
// (sadly, we cannot update this value later on if only 6 byte commands
// are supported, but the block_io module can live with that)
// are supported, but the block_io module can live with that)
max_blocks = min(max_blocks, 0xffff);
name = scsi_periph->compose_device_name(node, "disk/scsi");
if (name == NULL) {
SHOW_ERROR0(2, "Cannot compose device name");
goto err;
}
SHOW_FLOW(3, "name = %s", name);
// ready to register
{
device_attr attrs[] = {
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_DSK_MODULE_NAME }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: B_BLOCK_IO_MODULE_NAME }},
// tell block_io whether the device is removable
{ "removable", B_UINT8_TYPE, { ui8: device_inquiry->removable_medium }},
// tell which name we want to have in devfs
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
{ "removable", B_UINT8_TYPE, { ui8: deviceInquiry->removable_medium }},
// impose own max block restriction
{ B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, B_UINT32_TYPE, { ui32: max_blocks }},
// in general, any disk can be a BIOS drive (even ZIP-disks)
@@ -147,16 +117,7 @@ das_device_added(device_node_handle node)
{ NULL }
};
status_t res = pnp->register_device(node, attrs, NULL, &node);
free(name);
free(device_inquiry);
return res;
return pnp->register_node(node, SCSI_DSK_MODULE_NAME, attrs, NULL,
NULL);
}
err:
free(device_inquiry);
return B_ERROR;
}
@@ -3,12 +3,7 @@
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI Disk Driver
File handle management.
*/
/*! File handle management. */
#include "scsi_dsk_int.h"
@@ -29,8 +24,8 @@ das_open(das_device_info *device, das_handle_info **handle_out)
handle->device = device;
res = scsi_periph->handle_open(device->scsi_periph_device,
(periph_handle_cookie)handle,
res = scsi_periph->handle_open(device->scsi_periph_device,
(periph_handle_cookie)handle,
&handle->scsi_periph_handle);
if (res < 0) {
free(handle);
@@ -39,7 +34,7 @@ das_open(das_device_info *device, das_handle_info **handle_out)
SHOW_FLOW0(3, "opened");
*handle_out = handle;
*handle_out = handle;
return B_OK;
}
@@ -1,13 +1,10 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Part of Open SCSI Disk Driver
Main file.
You'll find das_... all over the place. This stands for
"Direct Access Storage" which is the official SCSI name for
normal (floppy/hard/ZIP)-disk drives.
@@ -28,6 +25,23 @@ device_manager_info *pnp;
block_io_for_driver_interface *gBlockIO;
static void
das_set_device(das_device_info *info, block_io_device device)
{
scsi_ccb *request;
info->block_io_device = device;
// and get (initial) capacity
request = info->scsi->alloc_ccb(info->scsi_device);
if (request == NULL)
return;
scsi_periph->check_capacity(info->scsi_periph_device, request);
info->scsi->free_ccb(request);
}
static status_t
das_read(das_handle_info *handle, const phys_vecs *vecs, off_t pos,
size_t num_blocks, uint32 block_size, size_t *bytes_transferred)
@@ -247,39 +261,43 @@ das_ioctl(das_handle_info *handle, int op, void *buf, size_t len)
static float
das_supports_device(device_node_handle parent, bool *_noConnection)
das_supports_device(device_node *parent)
{
char *bus;
uint8 device_type;
const char *bus;
uint8 deviceType;
// make sure parent is really the SCSI bus manager
if (pnp->get_attr_string(parent, B_DRIVER_BUS, &bus, false))
return B_ERROR;
if (pnp->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
return -1;
if (strcmp(bus, "scsi")) {
free(bus);
if (strcmp(bus, "scsi"))
return 0.0;
}
// check whether it's really a Direct Access Device
if (pnp->get_attr_uint8(parent, SCSI_DEVICE_TYPE_ITEM, &device_type, true) != B_OK
|| device_type != scsi_dev_direct_access) {
free(bus);
if (pnp->get_attr_uint8(parent, SCSI_DEVICE_TYPE_ITEM, &deviceType, true)
!= B_OK || deviceType != scsi_dev_direct_access)
return 0.0;
}
free(bus);
return 0.6;
}
static void
das_get_paths(const char ***_bus, const char ***_device)
static status_t
das_publish_device(void *_cookie)
{
static const char *kBus[] = { "scsi", NULL };
das_device_info *device = (das_device_info *)_cookie;
status_t status;
char *name;
*_bus = kBus;
*_device = NULL;
name = scsi_periph->compose_device_name(device->node, "disk/scsi");
if (name == NULL)
return B_ERROR;
status = pnp->publish_device(device->node, name,
B_BLOCK_IO_DEVICE_MODULE_NAME);
free(name);
return status;
}
@@ -304,7 +322,7 @@ module_dependency module_dependencies[] = {
{}
};
block_device_interface scsi_dsk_module = {
block_device_interface sSCSIDiskModule = {
{
{
SCSI_DSK_MODULE_NAME,
@@ -315,13 +333,13 @@ block_device_interface scsi_dsk_module = {
das_supports_device,
das_device_added,
das_init_device,
(status_t (*) (void *))das_uninit_device,
NULL, // remove device
NULL, // cleanup device
das_get_paths,
das_uninit_device,
das_publish_device,
NULL, // rescan
},
(status_t (*)(block_device_device_cookie, block_device_handle_cookie *))&das_open,
(void (*)(block_device_cookie *, block_io_device)) &das_set_device,
(status_t (*)(block_device_cookie *, block_device_handle_cookie *))&das_open,
(status_t (*)(block_device_handle_cookie)) &das_close,
(status_t (*)(block_device_handle_cookie)) &das_free,
@@ -333,10 +351,7 @@ block_device_interface scsi_dsk_module = {
(status_t (*)(block_device_handle_cookie, int, void *, size_t))&das_ioctl,
};
#if !_BUILDING_kernel && !BOOT
_EXPORT
module_info *modules[] = {
(module_info *)&scsi_dsk_module,
(module_info *)&sSCSIDiskModule,
NULL
};
#endif
@@ -4,11 +4,9 @@
*/
/*
Part of Open SCSI Disk Driver
Peripheral driver to handle any kind of SCSI disks,
i.e. hard disk and floopy disks (ZIP etc.)
Much work is done by scsi_periph and blkdev.
*/
@@ -17,6 +15,6 @@
#include <device_manager.h>
#define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/device_v1"
#define SCSI_DSK_MODULE_NAME "drivers/disk/scsi/scsi_dsk/driver_v1"
#endif /* _SCSI_DSK_H */
@@ -23,19 +23,20 @@
#include "wrapper.h"
// must start as block_device_cookie
typedef struct das_device_info {
device_node_handle node;
device_node *node;
scsi_periph_device scsi_periph_device;
scsi_device scsi_device;
scsi_device_interface *scsi;
block_io_device block_io_device;
uint64 capacity;
uint32 block_size;
bool removable; // true, if device is removable
bool removable; // true, if device is removable
} das_device_info;
typedef struct das_handle_info {
scsi_periph_handle scsi_periph_handle;
das_device_info *device;
@@ -47,21 +48,18 @@ extern scsi_periph_callbacks callbacks;
extern block_io_for_driver_interface *gBlockIO;
// device_mgr.c
// device.c
status_t das_init_device(device_node_handle node, void *user_cookie, void **cookie);
status_t das_uninit_device(das_device_info *device);
status_t das_device_added(device_node_handle node);
status_t das_device_added(device_node *node);
status_t das_init_device(device_node *node, void **cookie);
void das_uninit_device(void *cookie);
// handle_mgr.c
// scsi_dsk.c
status_t das_open(das_device_info *device, das_handle_info **handle_out);
status_t das_close(das_handle_info *handle);
status_t das_free(das_handle_info *handle);
// scsi_dsk.c
void das_set_capacity(das_device_info *device, uint64 capacity,
uint32 block_size);
-1
View File
@@ -3,7 +3,6 @@ SubDir HAIKU_TOP src add-ons kernel generic ;
SubInclude HAIKU_TOP src add-ons kernel generic atomizer ;
SubInclude HAIKU_TOP src add-ons kernel generic block_io ;
SubInclude HAIKU_TOP src add-ons kernel generic dpc ;
SubInclude HAIKU_TOP src add-ons kernel generic fast_log ;
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
SubInclude HAIKU_TOP src add-ons kernel generic mpu401 ;
+62 -125
View File
@@ -3,16 +3,9 @@
* Distributed under the terms of the MIT License.
*/
/*
Part of Open block device manager
Actual I/O.
Main file.
*/
#include "block_io_private.h"
#include <stdio.h>
@@ -37,7 +30,7 @@ device_manager_info *pnp;
static status_t
block_io_open(block_io_device_info *device, uint32 flags,
block_io_open(block_io_device_info *device, const char *path, int openMode,
block_io_handle_info **res_handle)
{
block_io_handle_info *handle;
@@ -142,7 +135,7 @@ static status_t
store_bios_drive_in_node(block_io_device_info *device)
{
device_attr attribute = {
B_BLOCK_DEVICE_BIOS_ID, B_UINT8_TYPE, { ui8:
B_BLOCK_DEVICE_BIOS_ID, B_UINT8_TYPE, { ui8:
device->bios_drive != NULL ? device->bios_drive->bios_id : 0 }
};
@@ -154,8 +147,8 @@ store_bios_drive_in_node(block_io_device_info *device)
* this must be called whenever someone wants to access BIOS infos about the drive;
* there are two reasons to not call this during probe():
* - perhaps nobody is interested in BIOS info
* - we need a working block_io device to handle lower level driver
* restrictions, so this method can only be safely called once the
* - we need a working block_io device to handle lower level driver
* restrictions, so this method can only be safely called once the
* node has been loaded
*/
@@ -169,11 +162,11 @@ find_bios_drive_info(block_io_handle_info *handle)
// SHOW_FLOW( 0, "%p", device );
// return immediately if BIOS info has already been found
// return immediately if BIOS info has already been found
if (device->bios_drive != NULL)
return;
// check whether BIOS info was found during one of the previous
// check whether BIOS info was found during one of the previous
// loads
if (pnp->get_attr_uint8(device->node, B_BLOCK_DEVICE_BIOS_ID, &bios_id, false) == B_OK) {
TRACE(("use previous BIOS ID 0x%x\n", bios_id));
@@ -253,7 +246,7 @@ find_bios_drive_info(block_io_handle_info *handle)
dprintf("Cannot distinguish between BIOS drives %x and %x without geometry\n",
drive->bios_id, colliding_drive->bios_id);
// this is nasty - we cannot reliable assign BIOS drive number.
// this is nasty - we cannot reliable assign BIOS drive number.
// if the user has luck, he "only" cannot install a boot manager;
// but if the boot drive is affected, he cannot even boot.
goto no_bios_drive;
@@ -265,11 +258,11 @@ find_bios_drive_info(block_io_handle_info *handle)
strcpy(drive->name, name);
device->bios_drive = drive;
// remember that to avoid testing next time
// remember that to avoid testing next time
store_bios_drive_in_node(device);
return;
no_bios_drive:
no_bios_drive:
device->bios_drive = NULL;
// remember that to avoid testing next time
@@ -307,8 +300,8 @@ block_io_ioctl(block_io_handle_info *handle, uint32 op, void *buffer, size_t len
TRACE(("GET_BIOS_GEOMETRY\n"));
// get real geometry from low level driver
status = device->interface->ioctl(handle->cookie, B_GET_GEOMETRY,
// get real geometry from low level driver
status = device->interface->ioctl(handle->cookie, B_GET_GEOMETRY,
geometry, sizeof(*geometry));
if (status != B_OK)
return status;
@@ -327,31 +320,10 @@ block_io_ioctl(block_io_handle_info *handle, uint32 op, void *buffer, size_t len
}
static status_t
block_io_register_device(device_node_handle parent)
{
TRACE(("block_io_register_device()\n"));
// ready to register at devfs
{
device_attr attrs[] = {
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: B_BLOCK_IO_MODULE_NAME }},
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "block_io" }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
{ NULL }
};
device_node_handle node;
return pnp->register_device(parent, attrs, NULL, &node);
}
}
static void
block_io_remove(device_node_handle node, void *cookie)
block_io_remove(void *cookie)
{
#if 0
uint8 bios_id;
//bios_drive *drive;
@@ -361,7 +333,6 @@ block_io_remove(device_node_handle node, void *cookie)
return;
// ToDo: this assumes private R5 kernel functions to be present
#if 0
for (drive = bios_drive_info; drive->bios_id != 0; ++drive) {
if (drive->bios_id == bios_id)
break;
@@ -376,26 +347,28 @@ block_io_remove(device_node_handle node, void *cookie)
static status_t
block_io_init_device(device_node_handle node, void *user_cookie, void **cookie)
block_io_init_device(void *_data, void **cookie)
{
block_device_cookie *data = (block_device_cookie *)_data;
block_io_device_info *device;
block_device_params params;
char *name, *tmp_name;
// const char *name;
// char *tmp_name;
uint8 is_bios_drive;
status_t res;
TRACE(("block_io_init_device()\n"));
// extract controller/protocoll restrictions from node
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_DMA_ALIGNMENT, &params.alignment, true) != B_OK)
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_ALIGNMENT, &params.alignment, true) != B_OK)
params.alignment = 0;
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &params.max_blocks, true) != B_OK)
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, &params.max_blocks, true) != B_OK)
params.max_blocks = 0xffffffff;
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_DMA_BOUNDARY, &params.dma_boundary, true) != B_OK)
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_BOUNDARY, &params.dma_boundary, true) != B_OK)
params.dma_boundary = ~0;
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, &params.max_sg_block_size, true) != B_OK)
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, &params.max_sg_block_size, true) != B_OK)
params.max_sg_block_size = 0xffffffff;
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_SG_BLOCKS, &params.max_sg_blocks, true) != B_OK)
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCKS, &params.max_sg_blocks, true) != B_OK)
params.max_sg_blocks = ~0;
// do some sanity check:
@@ -423,20 +396,13 @@ block_io_init_device(device_node_handle node, void *user_cookie, void **cookie)
return B_ERROR;
}
// allow "only" up to 512 sg entries
// allow "only" up to 512 sg entries
// (they consume 4KB and can describe up to 2MB virtual cont. memory!)
params.max_sg_blocks = min(params.max_sg_blocks, 512);
if (pnp->get_attr_uint8(node, B_BLOCK_DEVICE_IS_BIOS_DRIVE, &is_bios_drive, true) != B_OK)
if (pnp->get_attr_uint8(data->node, B_BLOCK_DEVICE_IS_BIOS_DRIVE, &is_bios_drive, true) != B_OK)
is_bios_drive = false;
// we don't really care about /dev name, but if it is
// missing, we will get a problem
if (pnp->get_attr_string(node, PNP_DEVFS_FILENAME, &name, true) != B_OK) {
dprintf("devfs filename is missing.\n");
return B_ERROR;
}
device = (block_io_device_info *)malloc(sizeof(*device));
if (device == NULL) {
res = B_NO_MEMORY;
@@ -445,14 +411,15 @@ block_io_init_device(device_node_handle node, void *user_cookie, void **cookie)
memset(device, 0, sizeof(*device));
device->node = node;
device->node = data->node;
res = benaphore_init(&device->lock, "block_device_mutex");
if (res < 0)
goto err2;
// construct a identifiable name for S/G pool
tmp_name = malloc(strlen(name) + strlen(" sg_lists") + 1);
#if 0
// construct a identifiable name for S/G pool
tmp_name = malloc(name + strlen(" sg_lists") + 1);
if (tmp_name == NULL) {
res = B_NO_MEMORY;
goto err3;
@@ -460,60 +427,53 @@ block_io_init_device(device_node_handle node, void *user_cookie, void **cookie)
strcpy(tmp_name, name);
strcat(tmp_name, " sg_lists");
#endif
// create S/G pool with initial size 1
// (else, we may be on the paging path and have no S/G entries at hand)
device->phys_vecs_pool = locked_pool->create(
device->phys_vecs_pool = locked_pool->create(
params.max_sg_blocks * sizeof(physical_entry),
sizeof( physical_entry ) - 1,
0, 16*1024, 32, 1, tmp_name, B_FULL_LOCK | B_CONTIGUOUS,
0, 16*1024, 32, 1, "block io sg lists", B_FULL_LOCK | B_CONTIGUOUS,
NULL, NULL, NULL);
free(tmp_name);
// free(tmp_name);
if (device->phys_vecs_pool == NULL) {
res = B_NO_MEMORY;
goto err3;
goto err3;
}
device->params = params;
device->is_bios_drive = is_bios_drive != 0;
res = pnp->init_driver(pnp->get_parent(node), device,
(driver_module_info **)&device->interface, (void **)&device->cookie);
if (res != B_OK)
goto err4;
pnp->get_driver(device->node, (driver_module_info **)&device->interface,
(void **)&device->cookie);
free(name);
device->interface->set_device(device->cookie, device);
TRACE(("done\n"));
*cookie = device;
return B_OK;
err4:
locked_pool->destroy(device->phys_vecs_pool);
err3:
benaphore_destroy(&device->lock);
err2:
free(device);
err1:
free(name);
pnp->uninit_driver(pnp->get_parent(node));
return res;
}
static status_t
block_io_uninit_device(block_io_device_info *device)
static void
block_io_uninit_device(void *_cookie)
{
pnp->uninit_driver(pnp->get_parent(device->node));
block_io_device_info *device = _cookie;
locked_pool->destroy(device->phys_vecs_pool);
benaphore_destroy(&device->lock);
free(device);
return B_OK;
}
@@ -533,8 +493,8 @@ block_io_init_buffer(void)
goto err1;
}
res = block_io_buffer_area = create_area("block_io_buffer",
(void **)&block_io_buffer, B_ANY_KERNEL_ADDRESS,
res = block_io_buffer_area = create_area("block_io_buffer",
(void **)&block_io_buffer, B_ANY_KERNEL_ADDRESS,
block_io_buffer_size, B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
if (res < 0)
goto err2;
@@ -564,7 +524,7 @@ err1:
static status_t
block_io_uninit_buffer(void)
{
delete_area(block_io_buffer_area);
delete_area(block_io_buffer_area);
delete_sem(block_io_buffer_lock);
return B_OK;
@@ -594,70 +554,47 @@ module_dependency module_dependencies[] = {
};
pnp_devfs_driver_info block_io_module = {
struct device_module_info sBlockIOModule = {
{
{
B_BLOCK_IO_MODULE_NAME,
0,
B_BLOCK_IO_DEVICE_MODULE_NAME,
0,
std_ops
},
NULL, // supports device
block_io_register_device,
block_io_init_device,
(status_t (*)( void * )) block_io_uninit_device,
block_io_remove,
NULL, // cleanup
NULL, // get paths
std_ops
},
(status_t (*)(void *, uint32, void **))block_io_open,
block_io_init_device,
block_io_uninit_device,
block_io_remove,
(status_t (*)(void *, const char *, int, void **))block_io_open,
(status_t (*)(void *))block_io_close,
(status_t (*)(void *))block_io_freecookie,
(status_t (*)(void *, uint32, void *, size_t))block_io_ioctl,
(status_t (*)(void *, off_t, void *, size_t *))block_io_read,
(status_t (*)(void *, off_t, const void *, size_t *))block_io_write,
NULL, // io
NULL,
NULL,
(status_t (*)(void *, int32, void *, size_t))block_io_ioctl,
(status_t (*)(void *, off_t, const iovec *, size_t, size_t *))block_io_readv,
(status_t (*)(void *, off_t, const iovec *, size_t, size_t *))block_io_writev
NULL, // select
NULL, // deselect
// (status_t (*)(void *, off_t, const iovec *, size_t, size_t *))block_io_readv,
// (status_t (*)(void *, off_t, const iovec *, size_t, size_t *))block_io_writev
};
static status_t
std_ops_for_driver(int32 op, ...)
{
// there is nothing to setup as this is a interface for
// drivers which are loaded by _us_
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
block_io_for_driver_interface block_io_for_driver_module = {
block_io_for_driver_interface sBlockIOForDriverModule = {
{
B_BLOCK_IO_FOR_DRIVER_MODULE_NAME,
0,
std_ops_for_driver
NULL
},
block_io_set_media_params,
};
module_info *modules[] = {
&block_io_module.info.info,
&block_io_for_driver_module.info,
&sBlockIOModule.info,
&sBlockIOForDriverModule.info,
NULL
};
@@ -34,15 +34,15 @@ typedef struct block_device_params {
// device info
typedef struct block_io_device_info {
device_node_handle node;
device_node *node;
block_device_interface *interface;
block_device_device_cookie cookie;
block_device_cookie *cookie;
benaphore lock; // used for access to following variables
uint32 block_size;
uint32 ld_block_size;
uint64 capacity;
block_device_params params;
bool is_bios_drive; // could be a BIOS drive
locked_pool_cookie phys_vecs_pool; // pool of temporary phys_vecs
@@ -82,11 +82,11 @@ extern device_manager_info *pnp;
// io.c
status_t block_io_readv(block_io_handle_info *handle, off_t pos, struct iovec *vec,
status_t block_io_readv(block_io_handle_info *handle, off_t pos, struct iovec *vec,
size_t vec_count, size_t *len);
status_t block_io_read(block_io_handle_info *handle, off_t pos, void *buf, size_t *len);
ssize_t block_io_writev(block_io_handle_info *handle, off_t pos, struct iovec *vec,
size_t vec_count, ssize_t *len);
ssize_t block_io_write(block_io_handle_info *handle, off_t pos, void *buf, size_t *len);
void block_io_set_media_params(block_io_device_info *device,
void block_io_set_media_params(block_io_device_info *device,
uint32 block_size, uint32 ld_block_size, uint64 capacity);
@@ -1,10 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel generic fast_log ;
UsePrivateHeaders kernel ;
KernelAddon fast_log :
clients.c
device.c
long_buffers.c
;
@@ -1,585 +0,0 @@
/*
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Fast logging facilities.
Client interface.
Every client opens a connection, passing a list of event
ids together with their description. All logging calls
write the encoded event into a buffer, using the event id
to save space. Once the logging data is to be read, the
buffer is decoded and written to the long buffers. The
same happens when a client closes a connection, as the
association between event ids and descriptions would be
lost.
The buffer is split into a lower and an upper half, each
of size fast_log_buffer_size. The currently active half
is determined by bit 31 of fast_log_buffer_offset_alloc:
zero means lower, one means upper half.
During write, fast_log_buffer_offset_alloc is first
incremented by the requested number of bytes atomically.
If there is enough space, the even data is copied into
the buffer and fast_log_buffer_offset_filled is
atomically incremented as well. This allows concurrent
filling by different threads without using any locking.
If the buffer is too short, logging data is discarded.
For read out, fast_log_buffer_offset_alloc
is atomically set to the beginning of the opposite buffer,
making sure that no further events are appended to the
previously active buffer. Then, we wait for
fast_log_buffer_offset having reached the value of
fast_log_buffer_alloc when it was reset, i.e. until
all active writes are completed. Now, the buffer can
be read out savely.
To detect buffer overflow, buffer halves are set to
zero before they are activated. If a write fails because
lack of space, nothing is writting to the buffer, though
fast_log_buffer_offset and fast_log_buffer_alloc are
incremented. This leads to an unwritten entry in the log,
which content remains zero. The easier way is to detect
whether fast_log_alloc is byond buffer size (which is
done as well), but because entries have different sizes,
we don't know which was the lastly written entry.
*/
#include "fast_log_int.h"
#include "dl_list.h"
#include <KernelExport.h>
#include <SupportDefs.h>
#include <stdio.h>
#include <string.h>
// one client connection
typedef struct fast_log_connection {
struct fast_log_connection *prev, *next;
// prefix in log
const char *prefix;
// list of event types
fast_log_event_type *types;
} fast_log_connection;
// one entry in logging buffer
typedef struct fast_log_entry {
// client handle.
// this must be first as it is checked against NULL
// by reader to detect overflown entries; moving it
// to a later offset would make reading of it dangerous
// as it could be located byond end of buffer
// (perhaps this could be handled as well, but it
// would make things more complicated)
fast_log_connection *handle;
// event type
int16 event;
// number of entries in "params"
int16 num_params;
// timestamp
bigtime_t time;
// parameters
uint32 params[1];
} fast_log_entry;
// list of clients
static fast_log_connection *fast_log_handles = NULL;
// to lock during access of fast_log_handles
sem_id fast_log_clients_sem;
// to lock during conversion of encoded buffer to long buffer
sem_id fast_log_convert_sem;
// logging buffer.
// it consists of 2*fast_log_buffer_size, see header
char *fast_log_buffer;
// offset in logging buffer for next write.
// bit 31 is set for upper buffer half and is rest for lower buffer half
uint32 fast_log_buffer_offset_alloc;
// offset of end of last write
uint32 fast_log_buffer_offset_filled;
// size of one half of log buffer
int fast_log_buffer_size = /*512*/ 16*1024;
// ToDo: cut down because of current allocator...
device_manager_info *pnp;
/** convert event code to text
* text_buffer - buffer used if text must is composed manually
* (must be at least 24 characters long)
*/
static const char *
fast_log_event2text(fast_log_connection *handle, int16 event, char *text_buffer)
{
fast_log_event_type *type;
for (type = handle->types; type->event != 0; ++type) {
if (type->event == event)
return type->description;
}
// longest message is 11 characters + 11 integer characters + zero byte
sprintf(text_buffer, "unknown (%d)", event);
return text_buffer;
}
/** decode one entry and write it to long buffer */
static void
fast_log_decode_entry(fast_log_entry *entry)
{
fast_log_connection *handle = entry->handle;
char buffer[100];
uint64 time;
uint32 min, sec, mill, mic;
char text_buffer[30];
int i;
time = entry->time; //entry->tsc / (sysinfo.cpu_clock_speed / 1000000);
mic = time % 1000;
time /= 1000;
mill = time % 1000;
time /= 1000;
sec = time % 60;
time /= 60;
min = time;
sprintf(buffer, "%03ld:%02ld:%03ld.%03ld ", min, sec, mill, mic);
fast_log_write_long_log(buffer);
fast_log_write_long_log(handle->prefix);
fast_log_write_long_log(": ");
fast_log_write_long_log(fast_log_event2text(handle, entry->event, text_buffer));
fast_log_write_long_log(" ");
for (i = 0; i < entry->num_params; ++i) {
if (i > 0)
fast_log_write_long_log(", ");
sprintf(buffer, "%08x", (uint)entry->params[i]);
fast_log_write_long_log(buffer);
}
fast_log_write_long_log("\n");
}
/** flush all compressed logging entries to long log */
void
fast_log_flush_buffer(void)
{
uint32 offset;
uint32 start, new_start, new_offset_alloc, size;
int i;
acquire_sem(fast_log_convert_sem);
// flip between lower and upper half of buffer
if ((fast_log_buffer_offset_alloc & (1L << 31)) == 0) {
start = 0;
new_start = fast_log_buffer_size;
new_offset_alloc = 1L << 31;
} else {
start = fast_log_buffer_size;
new_start = 0;
new_offset_alloc = 0;
}
// reset new buffer to zero to detect uninitialized, overflown entries
memset(fast_log_buffer + new_start, 0, fast_log_buffer_size);
// swap buffers
size = atomic_set((vint32*)&fast_log_buffer_offset_alloc, new_offset_alloc);
// get rid of bit 31 flag
size &= ~(1 << 31);
// decrement offset of filled data by number of bytes allocated when
// the buffer was swapped; if all writers are done, the offset is
// >= 0 now, if some writers aren't finished, it is < 0
atomic_add(&fast_log_buffer_offset_filled, -size);
// wait until all writers are finished
for (i = 1000000; i >= 0; --i) {
if ((int32)fast_log_buffer_offset_filled >= 0)
break;
spin(1);
// ToDo: spin?? If that should be a "yield", it should be snooze(1).
}
// perhaps we are in a spinlock or something nasty like that,
// so the writer is blocked by us
if (i < 0) {
fast_log_write_long_log("<TIME-OUT> during waiting for log writers; some "
"events got lost; perhaps a client disconnected with a spinlock hold\n");
}
// dprintf( "start=%d, size=%d\n", (int)start, (int)size );
// uncompress log
for (offset = 0; offset < size; ) {
fast_log_entry *entry;
// check whether there was an overflow when the buffer
// had zero bytes left
if (offset > (uint32)fast_log_buffer_size) {
fast_log_write_long_log("<TRUNCATED1>\n");
break;
}
entry = (fast_log_entry *)&fast_log_buffer[start + offset];
// check for overflow when the buffer had some bytes left;
// in this case, the entry is uninitialized and thus contains
// all zeros
if (entry->handle == NULL) {
fast_log_write_long_log( "<TRUNCATED2>\n" );
// the entry may be partially byond end of buffer, so
// we must not access any other element of the entry
break;
} else {
// normal entry, so it's time to decode it
fast_log_decode_entry(entry);
}
offset += sizeof(fast_log_entry)
+ (entry->num_params - 1) * sizeof(entry->params[0]);
}
release_sem(fast_log_convert_sem);
}
/** start logging of one client */
static fast_log_handle
fast_log_start_log(const char *prefix, fast_log_event_type types[])
{
fast_log_connection *handle;
handle = malloc(sizeof(*handle));
if (handle == NULL)
return NULL;
handle->prefix = prefix;
handle->types = types;
acquire_sem(fast_log_clients_sem);
ADD_DL_LIST_HEAD(handle, fast_log_handles, );
release_sem(fast_log_clients_sem);
return handle;
}
/** close connection of one client */
static void
fast_log_stop_log(fast_log_handle handle)
{
if (handle == NULL)
return;
fast_log_flush_buffer();
acquire_sem(fast_log_clients_sem);
REMOVE_DL_LIST(handle, fast_log_handles, );
release_sem(fast_log_clients_sem);
free(handle);
}
#define ENTRY_SIZE(num_params) (sizeof(fast_log_entry) + sizeof(uint32) * ((num_params)-1))
/** allocate space in log */
static fast_log_entry *
fast_log_alloc_entry(fast_log_handle handle, int num_params)
{
uint32 offset, real_offset, chunk_offset;
fast_log_entry *entry;
if (handle == NULL)
return NULL;
// alloc space in buffer
offset = atomic_add( &fast_log_buffer_offset_alloc, ENTRY_SIZE( num_params ));
real_offset = offset & ~(1L << 31);
chunk_offset = ((offset & (1L << 31)) == 0 ? 0 : fast_log_buffer_size);
// take care of bit 31 trick to get the address of the new entry
entry = (fast_log_entry *)&fast_log_buffer[chunk_offset + real_offset];
if (real_offset + ENTRY_SIZE( num_params ) < (uint32)fast_log_buffer_size) {
// there is enough space in buffer, so we can fill it
entry->time = system_time();
entry->handle = handle;
entry->num_params = num_params;
return entry;
} else {
// buffer overflow, return NULL to notify caller
atomic_add( &fast_log_buffer_offset_filled, ENTRY_SIZE( num_params ));
return NULL;
}
}
/** log event without parameters */
static void
fast_log_log_0(fast_log_handle handle, int event)
{
fast_log_entry *entry;
entry = fast_log_alloc_entry(handle, 0);
if (entry != NULL) {
entry->event = event;
atomic_add(&fast_log_buffer_offset_filled, ENTRY_SIZE(0));
}
}
/** log event with one parameter */
static void
fast_log_log_1(fast_log_handle handle, int event, uint32 param1)
{
fast_log_entry *entry;
entry = fast_log_alloc_entry(handle, 1);
if (entry != NULL) {
entry->event = event;
entry->params[0] = param1;
atomic_add(&fast_log_buffer_offset_filled, ENTRY_SIZE(1));
}
}
/** log event with two parameters */
static void
fast_log_log_2(fast_log_handle handle, int event, uint32 param1, uint32 param2)
{
fast_log_entry *entry;
entry = fast_log_alloc_entry(handle, 2);
if (entry != NULL) {
entry->event = event;
entry->params[0] = param1;
entry->params[1] = param2;
atomic_add(&fast_log_buffer_offset_filled, ENTRY_SIZE(2));
}
}
/** log event with three parameters */
static void
fast_log_log_3(fast_log_handle handle, int event,
uint32 param1, uint32 param2, uint32 param3)
{
fast_log_entry *entry;
entry = fast_log_alloc_entry(handle, 3);
if (entry != NULL) {
entry->event = event;
entry->params[0] = param1;
entry->params[1] = param2;
entry->params[2] = param3;
atomic_add(&fast_log_buffer_offset_filled, ENTRY_SIZE(3));
}
}
/** log event with four parameters */
static void
fast_log_log_4(fast_log_handle handle, int event, uint32 param1,
uint32 param2, uint32 param3, uint32 param4)
{
fast_log_entry *entry;
entry = fast_log_alloc_entry(handle, 4);
if (entry != NULL) {
entry->event = event;
entry->params[0] = param1;
entry->params[1] = param2;
entry->params[2] = param3;
entry->params[3] = param4;
atomic_add(&fast_log_buffer_offset_filled, ENTRY_SIZE(4));
}
}
/** log event with n parameters */
static void
fast_log_log_n(fast_log_handle handle, int event, int num_params, ...)
{
fast_log_entry *entry;
va_list vl;
entry = fast_log_alloc_entry(handle, num_params);
if (entry != NULL) {
int i;
va_start(vl, num_params);
entry->event = event;
for (i = 0; i < num_params; ++i) {
entry->params[i] = va_arg(vl, int);
}
va_end(vl);
atomic_add(&fast_log_buffer_offset_filled, ENTRY_SIZE(num_params));
}
}
/** clean up client structures */
static void
fast_log_uninit_clients()
{
free(fast_log_buffer);
delete_sem(fast_log_clients_sem);
delete_sem(fast_log_convert_sem);
}
/** init client structures.
* you must call fast_log_uninit_clients on fail
*/
static status_t
fast_log_init_clients()
{
fast_log_buffer = NULL;
fast_log_clients_sem = -1;
fast_log_convert_sem = -1;
fast_log_clients_sem = create_sem(1, "fast_log_clients_sem");
if (fast_log_clients_sem < B_OK)
return fast_log_clients_sem;
fast_log_convert_sem = create_sem(1, "fast_log_convert_sem");
if (fast_log_convert_sem < B_OK)
return fast_log_convert_sem;
fast_log_buffer = malloc(2 * fast_log_buffer_size);
if (fast_log_buffer == NULL)
return B_NO_MEMORY;
memset(fast_log_buffer, 0, 2 * fast_log_buffer_size);
fast_log_buffer_offset_filled = fast_log_buffer_offset_alloc = 0;
return B_OK;
}
/** uninitialize module */
static status_t
fast_log_uninit(void)
{
fast_log_uninit_dev();
fast_log_uninit_long_buffer();
fast_log_uninit_clients();
return B_OK;
}
/** initialize module */
static status_t
fast_log_init(void)
{
status_t res;
if ((res = fast_log_init_long_buffer()) < B_OK)
goto err3;
if ((res = fast_log_init_clients()) < B_OK)
goto err2;
if ((res = fast_log_init_dev()) < B_OK)
// yes: don't call uninit for device.c
goto err2;
return B_OK;
err2:
fast_log_uninit_clients();
err3:
fast_log_uninit_long_buffer();
return res;
}
static status_t
fast_log_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
return fast_log_init();
case B_MODULE_UNINIT:
return fast_log_uninit();
default:
return B_ERROR;
}
}
module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
{}
};
// client interface
fast_log_info fast_log_module = {
{
FAST_LOG_MODULE_NAME,
0,
fast_log_std_ops
},
fast_log_start_log,
fast_log_stop_log,
fast_log_log_0,
fast_log_log_1,
fast_log_log_2,
fast_log_log_3,
fast_log_log_4,
fast_log_log_n
};
// embedded modules
module_info *modules[] = {
(module_info *)&fast_log_module,
(module_info *)&fast_log_devfs_module,
NULL
};
@@ -1,180 +0,0 @@
/*
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the MIT License.
*/
/*
Fast logging facilities.
Devfs interface.
Publishes a file where logging data can be read from
directly via read. Once read, the logging data is freed.
Obviously, you cannot seek in the file.
Concurrent reads are permitted, but you will have fun
merging read data.
*/
#include "fast_log_int.h"
#include <pnp_devfs.h>
#include <device_manager.h>
// Devfs node
device_node_handle fast_log_devfs_node;
static status_t
fast_log_devfs_open(void *device_cookie, uint32 flags, void **handle_cookie)
{
handle_cookie = NULL;
return B_OK;
}
static status_t
fast_log_devfs_close(void *cookie)
{
return B_OK;
}
static status_t
fast_log_devfs_free(void *cookie)
{
return B_OK;
}
static status_t
fast_log_devfs_control(void *cookie, uint32 op, void *data, size_t len)
{
return B_ERROR;
}
static status_t
fast_log_devfs_read(void *cookie, off_t position, void *data, size_t *num_bytes)
{
*num_bytes = fast_log_read_long(data, *num_bytes);
return B_OK;
}
static status_t
fast_log_devfs_write(void *cookie, off_t position, const void *data, size_t *num_bytes)
{
*num_bytes = 0;
return B_ERROR;
}
// #pragma mark -
/** create devfs entry */
static status_t
fast_log_create_devfs_entry(void)
{
status_t res;
device_attr attrs[] = {
{ 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 }},
{ NULL }
};
res = pnp->register_device(NULL, attrs, NULL, &fast_log_devfs_node);
if (res < 0)
fast_log_devfs_node = NULL;
return res;
}
static status_t
fast_log_devfs_init_device(device_node_handle node, void *user_cookie, void **cookie)
{
*cookie = NULL;
return B_OK;
}
static status_t
fast_log_devfs_uninit_device(void *cookie)
{
return B_OK;
}
static status_t
fast_log_devfs_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
// devfs interface
pnp_devfs_driver_info fast_log_devfs_module = {
{
{
FAST_LOG_DEVFS_MODULE_NAME,
0,
fast_log_devfs_std_ops
},
NULL,
NULL,
fast_log_devfs_init_device,
fast_log_devfs_uninit_device,
NULL,
NULL,
},
fast_log_devfs_open,
fast_log_devfs_close,
fast_log_devfs_free,
fast_log_devfs_control,
fast_log_devfs_read,
fast_log_devfs_write
};
/** cleanup devfs interface */
void
fast_log_uninit_dev(void)
{
if (fast_log_devfs_node != NULL)
pnp->unregister_device(fast_log_devfs_node);
}
/** init devfs interface */
status_t
fast_log_init_dev(void)
{
status_t res;
fast_log_devfs_node = NULL;
if ((res = fast_log_create_devfs_entry()) < 0)
return res;
return B_OK;
}
@@ -1,88 +0,0 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
/*
Macros for double linked lists
*/
#ifndef _DL_LIST_H
#define _DL_LIST_H
#define REMOVE_DL_LIST( item, head, prefix ) \
do { \
if( item->prefix##prev ) \
item->prefix##prev->prefix##next = item->prefix##next; \
else \
head = item->prefix##next; \
\
if( item->prefix##next ) \
item->prefix##next->prefix##prev = item->prefix##prev; \
} while( 0 )
#define ADD_DL_LIST_HEAD( item, head, prefix ) \
do { \
item->prefix##next = head; \
item->prefix##prev = NULL; \
\
if( (head) ) \
(head)->prefix##prev = item; \
\
(head) = item; \
} while( 0 )
#define REMOVE_CDL_LIST( item, head, prefix ) \
do { \
item->prefix##next->prefix##prev = item->prefix##prev; \
item->prefix##prev->prefix##next = item->prefix##next; \
\
if( item == (head) ) { \
if( item->prefix##next != item ) \
(head) = item->prefix##next; \
else \
(head) = NULL; \
} \
} while( 0 )
#define ADD_CDL_LIST_TAIL( item, type, head, prefix ) \
do { \
type *old_head = head; \
\
if( old_head ) { \
type *first, *last; \
\
first = old_head; \
last = first->prefix##prev; \
\
item->prefix##next = first; \
item->prefix##prev = last; \
first->prefix##prev = item; \
last->prefix##next = item; \
} else { \
head = item; \
item->prefix##next = item->prefix##prev = item; \
} \
} while( 0 )
#define ADD_CDL_LIST_HEAD( item, type, head, prefix ) \
do { \
type *old_head = head; \
\
head = item; \
if( old_head ) { \
type *first, *last; \
\
first = old_head; \
last = first->prefix##prev; \
\
item->prefix##next = first; \
item->prefix##prev = last; \
first->prefix##prev = item; \
last->prefix##next = item; \
} else { \
item->prefix##next = item->prefix##prev = item; \
} \
} while( 0 )
#endif
@@ -1,45 +0,0 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
/*
Fast logging facilities.
Internal header.
*/
#include <drivers/fast_log.h>
#include <malloc.h>
#include <pnp_devfs.h>
#include <device_manager.h>
// maximum number of long buffer
#define FAST_LOG_MAX_LONG_BUFFERS 256;
// size of one long buffer
#define FAST_LOG_LONG_BUFFER_SIZE (16*1024)
// name of dev interface module
#define FAST_LOG_DEVFS_MODULE_NAME "generic/fast_log/devfs/v1"
extern device_manager_info *pnp;
// long_buffers.c
void fast_log_write_long_log(const char *str);
void fast_log_flush_buffer(void);
size_t fast_log_read_long(char *buffer, size_t len);
status_t fast_log_init_long_buffer(void);
void fast_log_uninit_long_buffer(void);
// device.c
status_t fast_log_init_dev(void);
void fast_log_uninit_dev(void);
extern pnp_devfs_driver_info fast_log_devfs_module;
@@ -1,266 +0,0 @@
/*
** Copyright 2002/03, Thomas Kurschel. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
/*
Fast logging facilities.
Long buffer.
The internal log buffer uses encoded events and
cannot be decoded on demand as the event codes are
passed by the client and can be changed each time
the client connects. So, we store the decoded events
in long buffers which can be read from directly.
The long buffer is split up into several smaller
buffers that are allocated and freed on demand
to save space.
*/
#include "fast_log_int.h"
#include "dl_list.h"
#include <lock.h>
#include <string.h>
// one long buffer
typedef struct tagfast_log_long_buffer {
struct tagfast_log_long_buffer *next, *prev;
// content
char *data;
// offset for writing
size_t write_offset;
// offset for reading
size_t read_offset;
// size of buffer
size_t size;
} fast_log_long_buffer;
static fast_log_long_buffer
// list of long buffers
*fast_log_long_buffers,
// current buffer to write to
// (NULL if all long buffers are full)
*fast_log_cur_long_buffer;
static uint
// current number of long buffers
fast_log_num_long_buffers,
// maximum number of long buffers
fast_log_max_long_buffers;
// size of one long buffer
static size_t fast_log_long_buffer_size;
// true, if all long buffers are full
// (used to insert a proper message in logging)
static bool fast_log_long_overflow = false;
// grab this when you want to access a long buffer.
// you must make sure that no swapping occurs when holding this lock
static benaphore fast_log_long_buffer_ben;
// grab this when you read out long buffers.
// you are allowed to swap when you hold this lock;
// must be acquired before fast_log_long_buffer_ben
static benaphore fast_log_long_read_ben;
/** flush current long log buffer and allocate new one */
static status_t
fast_log_inc_long_buffer(void)
{
fast_log_long_buffer *buffer;
fast_log_cur_long_buffer = NULL;
// allocate new buffer if allowed and possible
if (fast_log_num_long_buffers >= fast_log_max_long_buffers)
return B_ERROR;
buffer = malloc(sizeof(*buffer) + fast_log_long_buffer_size);
if (buffer == NULL)
return B_NO_MEMORY;
memset(buffer, 0, sizeof(*buffer));
buffer->write_offset = 0;
buffer->read_offset = 0;
buffer->size = fast_log_long_buffer_size;
buffer->data = (char *)(buffer + 1);
ADD_CDL_LIST_TAIL(buffer, fast_log_long_buffer, fast_log_long_buffers, );
fast_log_cur_long_buffer = buffer;
return B_OK;
}
/** store string in long log, internal */
static status_t
fast_log_write_long_log_intern(const char *str)
{
size_t len;
len = strlen(str);
while (len > 0) {
fast_log_long_buffer *buffer;
size_t cur_len;
// get buffer, alloc a new one if there isn't one
if (fast_log_cur_long_buffer == NULL) {
if (fast_log_inc_long_buffer() != B_OK)
return B_ERROR;
}
buffer = fast_log_cur_long_buffer;
cur_len = min(len, buffer->size - buffer->write_offset);
memcpy(buffer->data + buffer->write_offset, str, cur_len);
buffer->write_offset += cur_len;
len -= cur_len;
str += cur_len;
if (buffer->write_offset == buffer->size) {
// next iteration will get a new one
fast_log_cur_long_buffer = NULL;
}
}
return B_OK;
}
/** store string in long log */
void
fast_log_write_long_log(const char *str)
{
benaphore_lock(&fast_log_long_buffer_ben);
// write pending "overflow" message
if (fast_log_long_overflow) {
if (fast_log_write_long_log_intern("<BUFFER OVERFLOW, increase max_long_buffers>\n") != B_OK)
goto err;
fast_log_long_overflow = false;
}
if (fast_log_write_long_log_intern(str) != B_OK)
fast_log_long_overflow = true;
err:
benaphore_unlock(&fast_log_long_buffer_ben);
}
/** free (first) long buffer */
static void
fast_log_free_long_buffer(void)
{
fast_log_long_buffer *buffer = fast_log_long_buffers;
REMOVE_CDL_LIST(buffer, fast_log_long_buffers, );
free(buffer);
}
/** read data from long buffers */
size_t
fast_log_read_long(char *data, size_t len)
{
size_t left_bytes = len;
// fill long buffer
fast_log_flush_buffer();
// make sure noone reads log concurrently
benaphore_lock(&fast_log_long_read_ben);
benaphore_lock(&fast_log_long_buffer_ben);
while (left_bytes > 0 && fast_log_long_buffers != NULL) {
size_t cur_len;
fast_log_long_buffer *buffer;
buffer = fast_log_long_buffers;
cur_len = min(left_bytes, buffer->write_offset - buffer->read_offset);
if (cur_len == 0)
break;
// "data" may be pagable, so release lock during memcpy
benaphore_unlock(&fast_log_long_buffer_ben);
memcpy(data, buffer->data + buffer->read_offset, cur_len);
benaphore_lock(&fast_log_long_buffer_ben);
buffer->read_offset += cur_len;
data += cur_len;
left_bytes -= cur_len;
// once a buffer is completely read, free it
if (buffer->read_offset == buffer->size) {
fast_log_free_long_buffer();
buffer = fast_log_long_buffers;
}
}
benaphore_unlock(&fast_log_long_buffer_ben);
benaphore_unlock(&fast_log_long_read_ben);
return len - left_bytes;
}
/** cleanup long buffers */
void
fast_log_uninit_long_buffer(void)
{
while (fast_log_long_buffers != NULL)
fast_log_free_long_buffer();
benaphore_destroy(&fast_log_long_buffer_ben);
benaphore_destroy(&fast_log_long_read_ben);
}
/** initialize long buffers.
* you must call "fast_log_uninit_long_buffer" on fail
*/
status_t
fast_log_init_long_buffer(void)
{
status_t res;
fast_log_long_buffer_ben.sem = -1;
fast_log_long_read_ben.sem = -1;
fast_log_long_buffers = fast_log_cur_long_buffer = NULL;
fast_log_num_long_buffers = 0;
fast_log_max_long_buffers = 256;
fast_log_long_buffer_size = 16*1024;
fast_log_long_overflow = false;
if ((res = benaphore_init(&fast_log_long_buffer_ben, "fast_log_long_buffer_ben")) < 0)
return res;
if ((res = benaphore_init( &fast_log_long_read_ben, "fast_log_long_read_ben")) < 0)
return res;
return res;
}
@@ -37,12 +37,19 @@ static ide_for_controller_interface *ide;
static device_manager_info *pnp;
static void
set_channel(ide_adapter_channel_info *channel, ide_channel ideChannel)
{
channel->ide_channel = ideChannel;
}
static status_t
ide_adapter_write_command_block_regs(ide_adapter_channel_info *channel,
ide_task_file *tf, ide_reg_mask mask)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
int i;
uint16 ioaddr = channel->command_block_base;
@@ -71,7 +78,7 @@ ide_adapter_read_command_block_regs(ide_adapter_channel_info *channel,
ide_task_file *tf, ide_reg_mask mask)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
int i;
uint16 ioaddr = channel->command_block_base;
@@ -94,7 +101,7 @@ static uint8
ide_adapter_get_altstatus(ide_adapter_channel_info *channel)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint16 altstatusaddr = channel->control_block_base;
if (channel->lost)
@@ -108,7 +115,7 @@ static status_t
ide_adapter_write_device_control(ide_adapter_channel_info *channel, uint8 val)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint16 device_control_addr = channel->control_block_base;
SHOW_FLOW(3, "%x", (int)val);
@@ -127,7 +134,7 @@ ide_adapter_write_pio(ide_adapter_channel_info *channel, uint16 *data,
int count, bool force_16bit)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint16 ioaddr = channel->command_block_base;
@@ -153,7 +160,7 @@ ide_adapter_read_pio(ide_adapter_channel_info *channel, uint16 *data,
int count, bool force_16bit)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint16 ioaddr = channel->command_block_base;
@@ -181,7 +188,7 @@ ide_adapter_inthand(void *arg)
{
ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg;
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint8 status;
SHOW_FLOW0(3, "");
@@ -211,7 +218,7 @@ ide_adapter_prepare_dma(ide_adapter_channel_info *channel,
const physical_entry *sgList, size_t sgListCount, bool writeToDevice)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint8 command;
uint8 status;
prd_entry *prd = channel->prdt;
@@ -226,14 +233,14 @@ ide_adapter_prepare_dma(ide_adapter_channel_info *channel,
SHOW_FLOW( 4, "%x, %x, %d", (int)prd->address, prd->count, prd->EOT);
}
pci->write_io_32(device, channel->bus_master_base + IDE_BM_PRDT_ADDRESS,
pci->write_io_32(device, channel->bus_master_base + IDE_BM_PRDT_ADDRESS,
(pci->read_io_32(device, channel->bus_master_base + IDE_BM_PRDT_ADDRESS) & 3)
| (B_HOST_TO_LENDIAN_INT32(pci->ram_address(device, (void *)channel->prdt_phys)) & ~3));
// reset interrupt and error signal
status = pci->read_io_8(device, channel->bus_master_base
+ IDE_BM_STATUS_REG) | IDE_BM_STATUS_INTERRUPT | IDE_BM_STATUS_ERROR;
pci->write_io_8(device,
pci->write_io_8(device,
channel->bus_master_base + IDE_BM_STATUS_REG, status);
// set data direction
@@ -255,7 +262,7 @@ static status_t
ide_adapter_start_dma(ide_adapter_channel_info *channel)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint8 command;
command = pci->read_io_8(device, channel->bus_master_base
@@ -275,7 +282,7 @@ static status_t
ide_adapter_finish_dma(ide_adapter_channel_info *channel)
{
pci_device_module_info *pci = channel->pci;
pci_device device = channel->device;
pci_device *device = channel->device;
uint8 command;
uint8 status, newStatus;
@@ -319,7 +326,7 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel)
static status_t
ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
ide_adapter_init_channel(device_node *node,
ide_adapter_channel_info **cookie, size_t total_data_size,
int32 (*inthand)(void *arg))
{
@@ -334,6 +341,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
TRACE("PCI-IDE: init channel...\n");
#if 0
if (1 /* debug */){
uint8 bus, device, function;
uint16 vendorID, deviceID;
@@ -345,6 +353,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
TRACE("PCI-IDE: bus %3d, device %2d, function %2d: vendor %04x, device %04x\n",
bus, device, function, vendorID, deviceID);
}
#endif
// get device data
if (pnp->get_attr_uint16(node, IDE_ADAPTER_COMMAND_BLOCK_BASE, &command_block_base, false) != B_OK
@@ -353,8 +362,11 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
|| pnp->get_attr_uint8(node, IDE_ADAPTER_CHANNEL_INDEX, &channel_index, false) != B_OK)
return B_ERROR;
if (pnp->init_driver(pnp->get_parent(node), NULL, NULL, (void **)&controller) != B_OK)
return B_ERROR;
{
device_node *parent = pnp->get_parent_node(node);
pnp->get_driver(parent, NULL, (void **)&controller);
pnp->put_node(parent);
}
channel = (ide_adapter_channel_info *)malloc(total_data_size);
if (channel == NULL) {
@@ -372,15 +384,14 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
channel->control_block_base = control_block_base;
channel->bus_master_base = controller->bus_master_base + (channel_index * 8);
channel->intnum = intnum;
channel->ide_channel = ide_channel;
channel->dmaing = false;
channel->inthand = inthand;
TRACE("PCI-IDE: bus master base %#x\n", channel->bus_master_base);
// PRDT must be contiguous, dword-aligned and must not cross 64K boundary
// PRDT must be contiguous, dword-aligned and must not cross 64K boundary
prdt_size = (IDE_ADAPTER_MAX_SG_COUNT * sizeof( prd_entry ) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
channel->prd_area = create_area("prd", (void **)&channel->prdt, B_ANY_KERNEL_ADDRESS,
channel->prd_area = create_area("prd", (void **)&channel->prdt, B_ANY_KERNEL_ADDRESS,
prdt_size, B_FULL_LOCK | B_CONTIGUOUS, 0);
if (channel->prd_area < B_OK) {
res = channel->prd_area;
@@ -392,7 +403,7 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
SHOW_FLOW(3, "virt=%p, phys=%x", channel->prdt, (int)channel->prdt_phys);
res = install_io_interrupt_handler(channel->intnum,
res = install_io_interrupt_handler(channel->intnum,
inthand, channel, 0);
if (res < 0) {
@@ -403,15 +414,14 @@ ide_adapter_init_channel(device_node_handle node, ide_channel ide_channel,
TRACE("PCI-IDE: init channel done\n");
// enable interrupts so the channel is ready to run
ide_adapter_write_device_control(channel, ide_devctrl_bit3);
*cookie = channel;
return B_OK;
err3:
delete_area(channel->prd_area);
err2:
pnp->uninit_driver(pnp->get_parent(node));
err:
free(channel);
@@ -419,7 +429,7 @@ err:
}
static status_t
static void
ide_adapter_uninit_channel(ide_adapter_channel_info *channel)
{
// disable IRQs
@@ -432,17 +442,13 @@ ide_adapter_uninit_channel(ide_adapter_channel_info *channel)
remove_io_interrupt_handler(channel->intnum, channel->inthand, channel);
pnp->uninit_driver( pnp->get_parent(channel->node));
delete_area(channel->prd_area);
free(channel);
return B_OK;
}
static void
ide_adapter_channel_removed(device_node_handle node, ide_adapter_channel_info *channel)
ide_adapter_channel_removed(ide_adapter_channel_info *channel)
{
SHOW_FLOW0( 3, "" );
@@ -455,18 +461,16 @@ ide_adapter_channel_removed(device_node_handle node, ide_adapter_channel_info *c
/** publish node of ide channel */
static status_t
ide_adapter_publish_channel(device_node_handle controller_node,
ide_adapter_publish_channel(device_node *controller_node,
const char *channel_module_name, uint16 command_block_base,
uint16 control_block_base, uint8 intnum, bool can_dma,
uint8 channel_index, const char *name, io_resource_handle *resources,
device_node_handle *node)
uint8 channel_index, const char *name, const io_resource *resources,
device_node **node)
{
device_attr attrs[] = {
// info about ourself and our consumer
{ 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 }},
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "IDE PCI" }},
{ B_DEVICE_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 }},
@@ -479,21 +483,21 @@ ide_adapter_publish_channel(device_node_handle controller_node,
SHOW_FLOW0(2, "");
return pnp->register_device(controller_node, attrs, resources, node);
return pnp->register_node(controller_node, channel_module_name, attrs,
resources, node);
}
/** detect IDE channel */
static status_t
ide_adapter_detect_channel(pci_device_module_info *pci, pci_device pci_device,
device_node_handle controller_node, const char *channel_module_name,
ide_adapter_detect_channel(pci_device_module_info *pci, pci_device *pci_device,
device_node *controller_node, const char *channel_module_name,
bool controller_can_dma, uint16 command_block_base, uint16 control_block_base,
uint16 bus_master_base, uint8 intnum, uint8 channel_index, const char *name,
device_node_handle *node, bool supports_compatibility_mode)
device_node **node, bool supports_compatibility_mode)
{
uint8 api;
io_resource_handle resource_handles[3];
SHOW_FLOW0( 3, "" );
@@ -549,42 +553,38 @@ ide_adapter_detect_channel(pci_device_module_info *pci, pci_device pci_device,
}
{
// allocate channel's I/O resources
io_resource resources[3] = {
{ IO_PORT, command_block_base, 8 },
{ IO_PORT, control_block_base, 1 },
{ B_IO_PORT, command_block_base, 8 },
{ B_IO_PORT, control_block_base, 1 },
{}
};
if (pnp->acquire_io_resources(resources, resource_handles) != B_OK) {
TRACE("PCI-IDE: Couldn't acquire channel resources %#x and %#x\n",
command_block_base, control_block_base);
return B_ERROR;
}
return ide_adapter_publish_channel(controller_node, channel_module_name,
command_block_base, control_block_base, intnum, controller_can_dma,
channel_index, name, resources, node);
}
return ide_adapter_publish_channel(controller_node, channel_module_name,
command_block_base, control_block_base, intnum, controller_can_dma,
channel_index, name, resource_handles, node);
}
static status_t
ide_adapter_init_controller(device_node_handle node, void *user_cookie,
ide_adapter_init_controller(device_node *node,
ide_adapter_controller_info **cookie, size_t total_data_size)
{
pci_device_module_info *pci;
pci_device device;
pci_device *device;
ide_adapter_controller_info *controller;
uint16 bus_master_base;
uint16 pcicmd;
// uint16 pcicmd;
// get device data
// get device data
if (pnp->get_attr_uint16(node, IDE_ADAPTER_BUS_MASTER_BASE, &bus_master_base, false) != B_OK)
return B_ERROR;
if (pnp->init_driver(pnp->get_parent(node), NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
return B_ERROR;
{
device_node *parent = pnp->get_parent_node(node);
pnp->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
pnp->put_node(parent);
}
controller = (ide_adapter_controller_info *)malloc(total_data_size);
if (controller == NULL)
@@ -610,51 +610,44 @@ ide_adapter_init_controller(device_node_handle node, void *user_cookie,
controller->device = device;
controller->lost = false;
controller->bus_master_base = bus_master_base;
*cookie = controller;
return B_OK;
}
static status_t
ide_adapter_uninit_controller(ide_adapter_controller_info *controller)
{
pnp->uninit_driver(pnp->get_parent(controller->node));
free(controller);
return B_OK;
}
static void
ide_adapter_controller_removed(device_node_handle node,
ide_adapter_controller_info *controller)
ide_adapter_uninit_controller(ide_adapter_controller_info *controller)
{
free(controller);
}
static void
ide_adapter_controller_removed(ide_adapter_controller_info *controller)
{
SHOW_FLOW0(3, "");
if (controller != NULL)
if (controller != NULL) {
// disable access instantly; unit_device takes care of unregistering ioports
atomic_or(&controller->lost, 1);
}
}
/** publish node of ide controller */
static status_t
ide_adapter_publish_controller(device_node_handle parent, uint16 bus_master_base,
io_resource_handle *resources, const char *controller_driver,
ide_adapter_publish_controller(device_node *parent, uint16 bus_master_base,
io_resource *resources, const char *controller_driver,
const char *controller_driver_type, const char *controller_name, bool can_dma,
bool can_cq, uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
device_node_handle *node)
device_node **node)
{
device_attr attrs[] = {
// info about ourself and our consumer
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: controller_driver }},
// properties of this controller for ide bus manager
// there are always max. 2 devices
// there are always max. 2 devices
// (unless this is a Compact Flash Card with a built-in IDE controller,
// which has exactly 1 device)
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
@@ -666,7 +659,7 @@ ide_adapter_publish_controller(device_node_handle parent, uint16 bus_master_base
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: controller_name }},
// DMA properties
// data must be word-aligned;
// data must be word-aligned;
// warning: some controllers are more picky!
{ B_BLOCK_DEVICE_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: dma_alignment /*1*/}},
// one S/G block must not cross 64K boundary
@@ -683,20 +676,23 @@ ide_adapter_publish_controller(device_node_handle parent, uint16 bus_master_base
SHOW_FLOW0( 2, "" );
return pnp->register_device(parent, attrs, resources, node);
return pnp->register_node(parent, controller_driver, attrs, resources, node);
}
/** detect pure IDE controller, i.e. without channels */
static status_t
ide_adapter_detect_controller(pci_device_module_info *pci, pci_device pci_device,
device_node_handle parent, uint16 bus_master_base, const char *controller_driver,
ide_adapter_detect_controller(pci_device_module_info *pci, pci_device *pci_device,
device_node *parent, uint16 bus_master_base, const char *controller_driver,
const char *controller_driver_type, const char *controller_name, bool can_dma,
bool can_cq, uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
device_node_handle *node)
device_node **node)
{
io_resource_handle resource_handles[2];
io_resource resources[2] = {
{ B_IO_PORT, bus_master_base, 16 },
{}
};
SHOW_FLOW0( 3, "" );
@@ -705,43 +701,31 @@ ide_adapter_detect_controller(pci_device_module_info *pci, pci_device pci_device
return B_ERROR;
}
{
io_resource resources[2] = {
{ IO_PORT, bus_master_base, 16 },
{}
};
if (pnp->acquire_io_resources(resources, resource_handles) != B_OK) {
TRACE("PCI-IDE: Couldn't acquire controller resource %#x\n", bus_master_base);
return B_ERROR;
}
}
return ide_adapter_publish_controller(parent, bus_master_base, resource_handles,
return ide_adapter_publish_controller(parent, bus_master_base, resources,
controller_driver, controller_driver_type, controller_name, can_dma, can_cq,
dma_alignment, dma_boundary, max_sg_block_size, node);
}
static status_t
ide_adapter_probe_controller(device_node_handle parent, const char *controller_driver,
ide_adapter_probe_controller(device_node *parent, const char *controller_driver,
const char *controller_driver_type, const char *controller_name,
const char *channel_module_name, bool can_dma, bool can_cq, uint32 dma_alignment,
uint32 dma_boundary, uint32 max_sg_block_size, bool supports_compatibility_mode)
{
pci_device_module_info *pci;
pci_device device;
pci_device *device;
uint16 command_block_base[2];
uint16 control_block_base[2];
uint16 bus_master_base;
device_node_handle controller_node, channels[2];
device_node *controller_node;
device_node *channels[2];
uint8 intnum;
status_t res;
SHOW_FLOW0( 3, "" );
if (pnp->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
return B_ERROR;
pnp->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4 );
control_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 4, 4);
@@ -756,13 +740,13 @@ ide_adapter_probe_controller(device_node_handle parent, const char *controller_d
control_block_base[1] &= PCI_address_io_mask;
bus_master_base &= PCI_address_io_mask;
res = ide_adapter_detect_controller(pci, device, parent, bus_master_base,
res = ide_adapter_detect_controller(pci, device, parent, bus_master_base,
controller_driver, controller_driver_type, controller_name, can_dma,
can_cq, dma_alignment, dma_boundary, max_sg_block_size, &controller_node);
// don't register if controller is already registered!
// (happens during rescan; registering new channels would kick out old channels)
if (res != B_OK || controller_node == NULL)
goto err;
return res;
// ignore errors during registration of channels - could be a simple rescan collision
ide_adapter_detect_channel(pci, device, controller_node, channel_module_name,
@@ -772,14 +756,8 @@ ide_adapter_probe_controller(device_node_handle parent, const char *controller_d
ide_adapter_detect_channel(pci, device, controller_node, channel_module_name,
can_dma, command_block_base[1], control_block_base[1], bus_master_base,
intnum, 1, "Secondary Channel", &channels[1], supports_compatibility_mode);
pnp->uninit_driver(parent);
return B_OK;
err:
pnp->uninit_driver(parent);
return res;
}
@@ -811,21 +789,23 @@ static ide_adapter_interface adapter_interface = {
std_ops
},
set_channel,
ide_adapter_write_command_block_regs,
ide_adapter_read_command_block_regs,
ide_adapter_get_altstatus,
ide_adapter_write_device_control,
ide_adapter_write_pio,
ide_adapter_read_pio,
ide_adapter_prepare_dma,
ide_adapter_start_dma,
ide_adapter_finish_dma,
ide_adapter_inthand,
ide_adapter_init_channel,
ide_adapter_uninit_channel,
ide_adapter_channel_removed,
@@ -21,16 +21,16 @@
char *
periph_compose_device_name(device_node_handle node, const char *prefix)
periph_compose_device_name(device_node *node, const char *prefix)
{
uint8 pathID, targetID, targetLUN, isPrimary, type;
uint8 pathID, targetID, targetLUN, type;
char name[128];
uint32 channel;
if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &pathID, true) != B_OK
|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &targetID, true) != B_OK
|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_LUN_ITEM, &targetLUN, true) != B_OK)
return NULL;
return NULL;
// IDE devices have a different naming scheme
@@ -55,7 +55,7 @@ periph_compose_device_name(device_node_handle node, const char *prefix)
status_t
periph_register_device(periph_device_cookie periph_device, scsi_periph_callbacks *callbacks,
scsi_device scsi_device, scsi_device_interface *scsi, device_node_handle node,
scsi_device scsi_device, scsi_device_interface *scsi, device_node *node,
bool removable, scsi_periph_device *driver)
{
scsi_periph_device_info *device;
@@ -87,7 +87,7 @@ periph_register_device(periph_device_cookie periph_device, scsi_periph_callbacks
device->next_tag_action = 0;
device->rw10_enabled = true;
// launch sync daemon
// launch sync daemon
res = register_kernel_daemon(periph_sync_queue_daemon, device, 60*10);
if (res != B_OK)
goto err2;
+10 -12
View File
@@ -54,7 +54,7 @@ periph_read_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
int err;
uint32 pos = pos64;
// don't test rw10_enabled restrictions - this flag may get changed
// don't test rw10_enabled restrictions - this flag may get changed
request = device->scsi->alloc_ccb(device->scsi_device);
if (request == NULL)
@@ -73,7 +73,7 @@ periph_read_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
if (num_blocks > 0x100)
num_blocks = 0x100;
// no way to break the 21 bit address limit
// no way to break the 21 bit address limit
if (pos64 > 0x200000) {
err = B_BAD_VALUE;
goto abort;
@@ -95,7 +95,7 @@ periph_read_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
request->timeout = device->std_timeout;
// see whether daemon instructed us to post an ordered command;
// reset flag after read
SHOW_FLOW( 3, "flag=%x, next_tag=%x, ordered: %s",
SHOW_FLOW( 3, "flag=%x, next_tag=%x, ordered: %s",
(int)request->flags, (int)device->next_tag_action,
(request->flags & SCSI_ORDERED_QTAG) != 0 ? "yes" : "no" );
@@ -139,7 +139,7 @@ periph_read_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
acquire_sem(request->completion_sem);
// ask generic peripheral layer what to do now
// ask generic peripheral layer what to do now
res = periph_check_error(device, request);
switch (res.action) {
@@ -154,7 +154,7 @@ periph_read_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
break;
case err_act_invalid_req:
// if this was a 10 byte command, the device probably doesn't
// if this was a 10 byte command, the device probably doesn't
// support them, so disable them and retry
if (is_rw10) {
atomic_and(&device->rw10_enabled, 0);
@@ -173,7 +173,7 @@ periph_read_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
if (res.error_code == B_DEV_READ_ERROR && write)
return B_DEV_WRITE_ERROR;
return res.error_code;
return res.error_code;
abort:
device->scsi->free_ccb(request);
@@ -184,16 +184,14 @@ abort:
static status_t
inquiry(scsi_periph_device_info *device, scsi_inquiry *inquiry)
{
scsi_res_inquiry *device_inquiry = NULL;
const scsi_res_inquiry *device_inquiry = NULL;
size_t inquiry_len;
if (pnp->get_attr_raw(device->node, SCSI_DEVICE_INQUIRY_ITEM,
(void **)&device_inquiry, &inquiry_len, true) != B_OK)
if (pnp->get_attr_raw(device->node, SCSI_DEVICE_INQUIRY_ITEM,
(const void **)&device_inquiry, &inquiry_len, true) != B_OK)
return B_ERROR;
memcpy(inquiry, device_inquiry, min(inquiry_len, sizeof(scsi_inquiry)));
free(device_inquiry);
return B_OK;
}
@@ -253,7 +251,7 @@ raw_command(scsi_periph_device_info *device, raw_device_command *cmd)
cmd->scsi_status = request->device_status;
if ((request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data) {
memcpy(cmd->sense_data, request->sense,
memcpy(cmd->sense_data, request->sense,
min(cmd->sense_data_length, (size_t)SCSI_MAX_SENSE_SIZE - request->sense_resid));
}
@@ -21,7 +21,7 @@ typedef struct scsi_periph_device_info {
scsi_device scsi_device;
scsi_device_interface *scsi;
periph_device_cookie periph_device;
device_node_handle node;
device_node *node;
bool removal_requested;
@@ -54,7 +54,7 @@ extern device_manager_info *pnp;
void periph_media_changed(scsi_periph_device_info *device, scsi_ccb *ccb);
void periph_media_changed_public(scsi_periph_device_info *device);
status_t periph_get_media_status(scsi_periph_handle_info *handle);
err_res periph_send_start_stop(scsi_periph_device_info *device, scsi_ccb *request,
err_res periph_send_start_stop(scsi_periph_device_info *device, scsi_ccb *request,
bool start, bool with_LoEj);
@@ -80,9 +80,9 @@ status_t periph_check_capacity(scsi_periph_device_info *device, scsi_ccb *ccb);
status_t periph_register_device(periph_device_cookie periph_device,
scsi_periph_callbacks *callbacks, scsi_device scsi_device, scsi_device_interface *scsi,
device_node_handle node, bool removable, scsi_periph_device *driver);
device_node *node, bool removable, scsi_periph_device *driver);
status_t periph_unregister_device(scsi_periph_device_info *driver);
char *periph_compose_device_name(device_node_handle device_node, const char *prefix);
char *periph_compose_device_name(device_node *device_node, const char *prefix);
// io.c
@@ -93,7 +93,7 @@ status_t periph_read(scsi_periph_handle_info *handle, const phys_vecs *vecs,
status_t periph_write(scsi_periph_handle_info *handle, const phys_vecs *vecs,
off_t pos, size_t num_blocks, uint32 block_size, size_t *bytes_transferred,
int preferred_ccb_size);
status_t periph_ioctl(scsi_periph_handle_info *handle, int op,
status_t periph_ioctl(scsi_periph_handle_info *handle, int op,
void *buf, size_t len);
void periph_sync_queue_daemon(void *arg, int iteration);
@@ -103,12 +103,12 @@ void periph_sync_queue_daemon(void *arg, int iteration);
status_t periph_safe_exec(scsi_periph_device_info *device, scsi_ccb *request);
status_t periph_simple_exec(scsi_periph_device_info *device, void *cdb,
uchar cdb_len, void *data, size_t data_len, int ccb_flags);
// device_icons.c
status_t periph_get_icon(icon_type type, device_icon *data);
// sync.c
err_res periph_synchronize_cache(scsi_periph_device_info *device,
@@ -0,0 +1,34 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "BaseDevice.h"
BaseDevice::BaseDevice()
:
fNode(NULL),
fDeviceModule(NULL),
fDeviceData(NULL)
{
}
BaseDevice::~BaseDevice()
{
}
status_t
BaseDevice::InitDevice()
{
return B_ERROR;
}
void
BaseDevice::UninitDevice()
{
}
@@ -0,0 +1,122 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef BASE_DEVICE_H
#define BASE_DEVICE_H
#include <device_manager.h>
class BaseDevice {
public:
BaseDevice();
virtual ~BaseDevice();
device_node* Node() const { return fNode; }
virtual status_t InitDevice();
virtual void UninitDevice();
device_module_info* Module() const { return fDeviceModule; }
void* Data() const { return fDeviceData; }
bool HasSelect() const
{ return Module()->select != NULL; }
bool HasDeselect() const
{ return Module()->deselect != NULL; }
bool HasRead() const
{ return Module()->read != NULL; }
bool HasWrite() const
{ return Module()->write != NULL; }
bool HasIO() const
{ return Module()->io != NULL; }
virtual status_t Open(const char* path, int openMode,
void** _cookie);
status_t Read(void* cookie, off_t pos, void* buffer,
size_t* _length);
status_t Write(void* cookie, off_t pos, const void* buffer,
size_t* _length);
status_t IO(void* cookie, io_request* request);
status_t Control(void* cookie, int32 op, void* buffer,
size_t length);
virtual status_t Select(void* cookie, uint8 event, selectsync* sync);
status_t Deselect(void* cookie, uint8 event,
selectsync* sync);
status_t Close(void* cookie);
status_t Free(void* cookie);
protected:
device_node* fNode;
int32 fInitialized;
device_module_info* fDeviceModule;
void* fDeviceData;
};
inline status_t
BaseDevice::Open(const char* path, int openMode, void** _cookie)
{
return Module()->open(Data(), path, openMode, _cookie);
}
inline status_t
BaseDevice::Read(void* cookie, off_t pos, void* buffer, size_t* _length)
{
return Module()->read(cookie, pos, buffer, _length);
}
inline status_t
BaseDevice::Write(void* cookie, off_t pos, const void* buffer, size_t* _length)
{
return Module()->write(cookie, pos, buffer, _length);
}
inline status_t
BaseDevice::IO(void* cookie, io_request* request)
{
return Module()->io(cookie, request);
}
inline status_t
BaseDevice::Control(void* cookie, int32 op, void* buffer, size_t length)
{
return Module()->control(cookie, op, buffer, length);
}
inline status_t
BaseDevice::Select(void* cookie, uint8 event, selectsync* sync)
{
return Module()->select(cookie, event, sync);
}
inline status_t
BaseDevice::Deselect(void* cookie, uint8 event, selectsync* sync)
{
return Module()->deselect(cookie, event, sync);
}
inline status_t
BaseDevice::Close(void* cookie)
{
return Module()->close(cookie);
}
inline status_t
BaseDevice::Free(void* cookie)
{
return Module()->free(cookie);
}
#endif // BASE_DEVICE_H
+8 -13
View File
@@ -3,19 +3,14 @@ SubDir HAIKU_TOP src system kernel device_manager ;
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
UsePrivateHeaders [ FDirName kernel util ] shared ;
KernelMergeObject kernel_device_manager.o :
attributes.c
device_manager.c
driver_loader.c
id_generator.c
io_resources.c
nodes.c
notifications.c
patterns.c
probe.cpp
registration.c
root_node.c
scan.c
KernelMergeObject kernel_device_manager.o :
BaseDevice.cpp
device_manager.cpp
devfs.cpp
id_generator.cpp
io_resources.cpp
legacy_drivers.cpp
# probe.cpp
settings.cpp
:
$(TARGET_KERNEL_PIC_CCFLAGS) -Wno-unused
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef DEVFS_PRIVATE_H
#define DEVFS_PRIVATE_H
#include <SupportDefs.h>
class BaseDevice;
status_t devfs_publish_device(const char* path, BaseDevice* device);
status_t devfs_get_device(dev_t device, ino_t node, BaseDevice** _device);
#endif /* DEVFS_PRIVATE_H */
File diff suppressed because it is too large Load Diff
@@ -1,223 +1,10 @@
/*
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef DEVICE_MANAGER_PRIVATE
#define DEVICE_MANAGER_PRIVATE
/*
Part of Device Manager
Internal header.
*/
#include <kdevice_manager.h>
#include <util/list.h>
#include <lock.h>
#define GENERATOR_MAX_ID 64
#define UNIVERSAL_SUBDIR "/universal"
#define GENERIC_SUBDIR "/generic"
// driver registration directories
#define PNP_DIR
#define SYSTEM_DRIVER_REGISTRATION "/boot/beos/system/add-ons/kernel/"PNP_DIR"registration/"
#define COMMON_DRIVER_REGISTRATION "/boot/home/config/add-ons/kernel/"PNP_DIR"registration/"
// info about ID generator
typedef struct id_generator {
struct list_link link;
struct id_generator *prev, *next;
int32 ref_count;
char *name;
uint32 num_ids;
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
} id_generator;
#ifndef DEVICE_MANAGER_PRIVATE_H
#define DEVICE_MANAGER_PRIVATE_H
// info about a node attribute
typedef struct device_attr_info {
struct device_attr_info *prev, *next;
int32 ref_count; // reference count
device_attr attr;
} device_attr_info;
// I/O resource
typedef struct io_resource_info {
struct io_resource_info *prev, *next;
device_node_info *owner; // associated node; NULL for temporary allocation
io_resource resource; // info about actual resource
} 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;
// root node
extern device_node_info *gRootNode;
// true, if user addons are disabled via safemode
extern bool disable_useraddons;
// # of allocate_io_resource() calls waiting for a retry
extern int pnp_resource_wait_count;
// semaphore for allocate_io_resource() call retry
extern sem_id pnp_resource_wait_sem;
// list of driver registration directories
extern const char *pnp_registration_dirs[];
// list of I/O memory, I/O ports and ISA DMA channels
extern io_resource_info *io_mem_list, *io_port_list, *isa_dma_list;
// nesting of pnp_load_boot_links calls
int pnp_fs_emulation_nesting;
#ifdef __cplusplus
extern "C" {
#endif
// attributes.c
device_attr_info *pnp_find_attr_nolock(device_node_handle node, const char *name,
bool recursive, type_code type);
status_t pnp_get_attr_uint8(device_node_handle node, const char *name,
uint8 *value, bool recursive);
status_t pnp_get_attr_uint8_nolock(device_node_handle node, const char *name,
uint8 *value, bool recursive);
status_t pnp_get_attr_uint16(device_node_handle node, const char *name,
uint16 *value, bool recursive);
status_t pnp_get_attr_uint16_nolock(device_node_handle node, const char *name,
uint16 *value, bool recursive);
status_t pnp_get_attr_uint32(device_node_handle node, const char *name,
uint32 *value, bool recursive);
status_t pnp_get_attr_uint32_nolock(device_node_handle node, const char *name,
uint32 *value, bool recursive);
status_t pnp_get_attr_uint64(device_node_handle node, const char *name,
uint64 *value, bool recursive);
status_t pnp_get_attr_uint64_nolock(device_node_handle node, const char *name,
uint64 *value, bool recursive);
status_t pnp_get_attr_string(device_node_handle node, const char *name,
char **value, bool recursive);
status_t pnp_get_attr_string_nolock(device_node_handle node, const char *name,
const char **value, bool recursive);
status_t pnp_get_attr_raw(device_node_handle node, const char *name,
void **data, size_t *len, bool recursive);
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);
status_t pnp_retrieve_attr(device_attr_handle attr, const device_attr **attr_content);
status_t pnp_write_attr(device_node_handle node, const device_attr *attr);
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);
// 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);
// id_generator.c
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 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 dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
device_node_info **new_node);
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_root(void);
device_node_info *dm_get_parent(device_node_info *node);
status_t device_manager_control(const char *subsystem, uint32 function, void *buffer, size_t bufferSize);
// notifications.c
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);
void pnp_finish_hook_call_nolock(device_node_info *node);
// patterns.c
status_t pnp_expand_pattern(device_node_info *node, const char *pattern,
char *dest, char *buffer, size_t *term_array, int *num_parts);
status_t pnp_expand_pattern_attr(device_node_info *node, const char *attr_name,
char **expanded);
// probe.cpp
status_t dm_register_child_device(device_node_info *node, const char *childName, bool checkSupport);
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 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);
// root_node.c
void dm_init_root_node(void);
// scan.c
status_t dm_rescan(device_node_handle node);
status_t dm_register_child_devices(device_node_info *node);
#ifdef __cplusplus
}
#endif
#endif /* DEVICE_MANAGER_PRIVATE_H */
#endif // DEVICE_MANAGER_PRIVATE_H
@@ -1,18 +1,13 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of the Device Manager
ID generator.
Generators are created on demand and deleted if all their
/*! Generators are created on demand and deleted if all their
IDs are freed. They have a ref_count which is increased
whenever someone messes with the generator.
whenever someone messes with the generator.
Whenever a generator is searched for, generator_lock is held.
@@ -20,19 +15,23 @@
contain up to GENERATOR_MAX_ID bits. This is a hard limit,
but it's simple to implement. If someone really needs lots of
IDs, we can still rewrite the code. For simplicity, we use
sGeneratorLock instead of a generator specific lock during
sGeneratorLock instead of a generator specific lock during
allocation; changing it is straightforward as everything
is prepared for that.
*/
#include "device_manager_private.h"
#include <KernelExport.h>
#include <util/list.h>
#include "id_generator.h"
#include <new>
#include <stdlib.h>
#include <string.h>
#include <KernelExport.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
//#define TRACE_ID_GENERATOR
#ifdef TRACE_ID_GENERATOR
@@ -41,52 +40,68 @@
# define TRACE(x) ;
#endif
#define GENERATOR_MAX_ID 64
struct list sGenerators;
static benaphore sGeneratorLock;
struct id_generator : DoublyLinkedListLinkImpl<id_generator> {
id_generator(const char* name)
:
ref_count(1),
name(strdup(name)),
num_ids(0)
{
memset(&alloc_map, 0, sizeof(alloc_map));
}
~id_generator()
{
free(name);
}
int32 ref_count;
char* name;
uint32 num_ids;
uint8 alloc_map[(GENERATOR_MAX_ID + 7) / 8];
};
typedef DoublyLinkedList<id_generator> GeneratorList;
/** Create new generator
* sGeneratorLock must be held
*/
GeneratorList sGenerators;
static mutex sLock;
static id_generator *
create_generator(const char *name)
/*! Create new generator.
sLock must be held.
*/
static id_generator*
create_generator(const char* name)
{
id_generator *generator;
TRACE(("create_generator(name: %s)\n", name));
generator = malloc(sizeof(*generator));
id_generator* generator = new(std::nothrow) id_generator(name);
if (generator == NULL)
return NULL;
memset(generator, 0, sizeof(*generator));
generator->name = strdup(name);
if (generator->name == NULL) {
free(generator);
delete generator;
return NULL;
}
generator->ref_count = 1;
list_add_link_to_head(&sGenerators, generator);
sGenerators.Add(generator);
return generator;
}
/** Allocate id */
/*! Allocate ID */
static int32
create_id_internal(id_generator *generator)
create_id_internal(id_generator* generator)
{
uint32 id;
TRACE(("create_id_internal(name: %s)\n", generator->name));
// see above: we use global instead of local lock
benaphore_lock(&sGeneratorLock);
// see above: we use global instead of local lock
MutexLocker _(sLock);
// simple bit search
for (id = 0; id < GENERATOR_MAX_ID; ++id) {
@@ -94,104 +109,92 @@ create_id_internal(id_generator *generator)
TRACE((" id: %lu\n", id));
generator->alloc_map[id / 8] |= 1 << (id & 7);
++generator->num_ids;
generator->num_ids++;
benaphore_unlock(&sGeneratorLock);
return id;
}
}
benaphore_unlock(&sGeneratorLock);
return B_ERROR;
}
/** Find generator by name
* sGeneratorLock must be held
*/
static id_generator *
find_generator(const char *name)
/*! Gets a generator by name, and acquires a reference to it.
sLock must be held.
*/
static id_generator*
get_generator(const char* name)
{
id_generator *generator = NULL;
TRACE(("find_generator(name: %s)\n", name));
while ((generator = list_get_next_item(&sGenerators, generator)) != NULL) {
GeneratorList::Iterator iterator = sGenerators.GetIterator();
while (iterator.HasNext()) {
id_generator* generator = iterator.Next();
if (!strcmp(generator->name, name)) {
// increase ref_count, so it won't go away
++generator->ref_count;
break;
// increase ref_count, so it won't go away
generator->ref_count++;
return generator;
}
}
return generator;
return NULL;
}
/** Decrease ref_count, deleting generator if not used anymore */
/*! Decrease ref_count, deleting generator if not used anymore */
static void
release_generator(id_generator *generator)
{
TRACE(("release_generator(name: %s)\n", generator->name));
benaphore_lock(&sGeneratorLock);
MutexLocker _(sLock);
if (--generator->ref_count == 0) {
// no one messes with generator
if (generator->num_ids == 0) {
TRACE((" Destroy %s\n", generator->name));
// no IDs is allocated - destroy generator
list_remove_link(generator);
free(generator->name);
free(generator);
sGenerators.Remove(generator);
delete generator;
}
}
benaphore_unlock(&sGeneratorLock);
}
// #pragma mark -
// Private kernel API
// #pragma mark - Private kernel API
status_t
void
dm_init_id_generator(void)
{
list_init(&sGenerators);
return benaphore_init(&sGeneratorLock, "id generator");
new(&sGenerators) GeneratorList;
mutex_init(&sLock, "id generator");
}
// #pragma mark -
// Public module API
// #pragma mark - Public module API
/** Create automatic ID */
/*! Create automatic ID */
int32
dm_create_id(const char *name)
dm_create_id(const char* name)
{
id_generator *generator;
int32 id;
// find generator, create new if not there
benaphore_lock(&sGeneratorLock);
// find generator, create new if not there
mutex_lock(&sLock);
generator = find_generator(name);
id_generator* generator = get_generator(name);
if (generator == NULL)
generator = create_generator(name);
benaphore_unlock(&sGeneratorLock);
mutex_unlock(&sLock);
if (generator == NULL)
return B_NO_MEMORY;
// get ID
id = create_id_internal(generator);
int32 id = create_id_internal(generator);
release_generator(generator);
@@ -200,21 +203,18 @@ dm_create_id(const char *name)
}
/** Free automatically generated ID */
/*! Free automatically generated ID */
status_t
dm_free_id(const char *name, uint32 id)
dm_free_id(const char* name, uint32 id)
{
id_generator *generator;
TRACE(("dm_free_id(name: %s, id: %ld)\n", name, id));
// find generator
benaphore_lock(&sGeneratorLock);
// find generator
mutex_lock(&sLock);
generator = find_generator(name);
id_generator* generator = get_generator(name);
benaphore_unlock(&sGeneratorLock);
mutex_unlock(&sLock);
if (generator == NULL) {
TRACE((" Generator %s doesn't exist\n", name));
@@ -226,7 +226,8 @@ dm_free_id(const char *name, uint32 id)
// make sure it's really allocated
// (very important to keep <num_ids> in sync
if ((generator->alloc_map[id / 8] & (1 << (id & 7))) == 0) {
dprintf("id %ld of generator %s wasn't allocated\n", id, generator->name);
dprintf("id %ld of generator %s wasn't allocated\n", id,
generator->name);
release_generator(generator);
return B_BAD_VALUE;
@@ -236,7 +237,5 @@ dm_free_id(const char *name, uint32 id)
generator->num_ids--;
release_generator(generator);
return B_OK;
}
@@ -0,0 +1,27 @@
/*
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef ID_GENERATOR_H
#define ID_GENERATOR_H
#include <SupportDefs.h>
#ifdef __cplusplus
extern "C" {
#endif
int32 dm_create_id(const char *name);
status_t dm_free_id(const char *name, uint32 id);
void dm_init_id_generator(void);
#ifdef __cplusplus
}
#endif
#endif /* ID_GENERATOR_H */
@@ -1,588 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
I/O resource manager.
I/O resources are allocated in two flavours:
1. explicit allocation for hardware detection ("temporary allocation")
2. implicit allocation for registered devices
If hardware detection fails, the resources are freed explicitely,
if it succeeds, ownership is transfered to the device node.
Resources allocation collision is handled in the following way:
- during ownership transfer to a device node, all other device nodes
that collide in terms of resources are removed
- if two temporary allocations collide, one must wait
- if a temporary allocation collides with a device node whose driver is
loaded, the temporary allocation fails (waiting for the driver may
be hopeless as the driver may stay in memory forever)
- if a temporary allocation collides with a device node whose driver is
not loaded, loading of the driver is blocked
To avoid deadlocks between temporary allocations, they are done atomically:
either the entire allocation succeeds or fails. If it fails because of a
collision with another temporary allocation, a complete retry is done as
soon as someone released some resource.
*/
#include "device_manager_private.h"
#include "dl_list.h"
#include <KernelExport.h>
#include <stdlib.h>
#include <string.h>
//#define TRACE_IO_RESOURCES
#ifdef TRACE_IO_RESOURCES
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
// forward declarations to avoid inlining
static void unblock_temporary_allocation(void);
static void release_range(io_resource_info **list, io_resource_info *resource,
io_resource_info *up_to);
static void unregister_colliding_node_range(io_resource_info *list,
io_resource_info *resource);
/** validate I/O resource data */
static status_t
validate_io_resource(io_resource *src)
{
TRACE(("validate_io_resource()\n"));
switch (src->type) {
case IO_MEM:
if (src->base + src->length < src->base)
return B_BAD_VALUE;
break;
case IO_PORT:
if ((uint16)src->base != 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->length != 1)
return B_BAD_VALUE;
break;
default:
return B_BAD_VALUE;
}
TRACE((" success!\n"));
return B_OK;
}
/** Allocate info structure for I/O resources */
static status_t
alloc_io_resource_info(io_resource *src, io_resource_info **dest_out)
{
io_resource_info *dest;
TRACE(("alloc_io_resource_info()\n"));
dest = calloc(1, sizeof(*dest));
if (dest == NULL)
return B_NO_MEMORY;
dest->owner = NULL;
dest->resource.type = src->type;
dest->resource.base = src->base;
dest->resource.length = src->length;
*dest_out = dest;
return B_OK;
}
/** Acquire I/O range; returns B_WOULD_BLOCK on collision with
* temporary allocation.
* gNodeLock must be held
*/
static status_t
acquire_range(io_resource_info **list, io_resource_info *resource)
{
io_resource_info *cur;
uint32 base = resource->resource.base;
uint32 length = resource->resource.length;
status_t res = B_OK;
TRACE(("acquire_range(base %lx, length %lx)\n", base, length));
for (cur = *list; cur != NULL; cur = cur->next) {
// 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((" collision\n"));
if (owner == NULL) {
// collision with temporary allocation - block ourself
TRACE((" collision with temporary allocation - retry later\n"));
res = B_WOULD_BLOCK;
break;
} else {
// collision with device
if (owner->loading + owner->load_count > 0) {
// driver is already loaded - give up
// (driver may get loaded forever)
TRACE((" collision with loaded driver - giving up\n"));
res = B_BUSY;
break;
} else {
// driver is not loaded - block loading
TRACE((" collision with unloaded driver - block driver %p\n", owner));
++owner->load_block_count;
}
}
}
}
if (cur != NULL) {
// collided with someone
TRACE((" Resource collision\n"));
release_range(list, resource, cur);
return res;
}
ADD_DL_LIST_HEAD(resource, *list, );
return B_OK;
}
/** Free I/O resource info */
static void
free_io_resource_info(io_resource_info *resource)
{
TRACE(("free_io_resource_info()\n"));
free(resource);
}
/** 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 held.
*/
static status_t
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, length = %lx)\n",
src->type, src->base, src->length));
res = validate_io_resource(src);
if (res != B_OK)
return res;
res = alloc_io_resource_info(src, &dest);
if (res != B_OK)
return res;
switch (src->type) {
case IO_MEM:
res = acquire_range(&io_mem_list, dest);
break;
case IO_PORT:
res = acquire_range(&io_port_list, dest);
break;
case ISA_DMA_CHANNEL:
res = acquire_range(&isa_dma_list, dest);
break;
}
if (res != B_OK)
// collided with someone
goto err;
*dest_out = dest;
TRACE((" done\n"));
return B_OK;
err:
free_io_resource_info(dest);
TRACE((" failed: %s\n", strerror(res)));
return res;
}
/** Release I/O resource.
* gNodeLock must be held
*/
static void
release_io_resource(io_resource_info *resource)
{
TRACE(("release_io_resource()\n"));
switch (resource->resource.type) {
case IO_MEM:
release_range(&io_mem_list, resource, NULL);
break;
case IO_PORT:
release_range(&io_port_list, resource, NULL);
break;
case ISA_DMA_CHANNEL:
release_range(&isa_dma_list, resource, NULL);
break;
}
free_io_resource_info(resource);
}
/** Release I/O range, which can be I/O memory, ports and ISA DMA channels
* up_to - up to but not including colliding range to be released
* (NULL for normal release, not-NULL if used during failed allocation)
* blocked users get notified;
* gNodeLock must be held
*/
static void
release_range(io_resource_info **list, io_resource_info *resource, io_resource_info *up_to)
{
io_resource_info *cur;
uint32 base = resource->resource.base;
uint32 length = resource->resource.length;
TRACE(("release_range()\n"));
for (cur = *list; cur != NULL && cur != up_to; cur = cur->next) {
if (cur == resource)
// ignore ourselves
continue;
// 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"));
if (owner != NULL) {
// collision with driver - unblock it
TRACE((" collision with driver - unblock driver %p\n", owner));
pnp_unblock_load(owner);
}
}
}
if (up_to == NULL) {
// normal release - remove from list and
// notify blocked temporary allocations
REMOVE_DL_LIST(resource, *list, );
unblock_temporary_allocation();
}
}
/** Wait until someone freed some resource or
* allocated some resource permanently.
* gNodeLock must be held.
*/
static void
wait_for_resources(void)
{
TRACE(("wait_for_resources()\n"));
++pnp_resource_wait_count;
// we have to release while waiting
benaphore_unlock(&gNodeLock);
acquire_sem(pnp_resource_wait_sem);
benaphore_lock(&gNodeLock);
}
/** Try to acquire list of resources.
* returns B_WOULD_BLOCK on collision with temporary allocation.
* gNodeLock must be held.
*/
static status_t
try_acquire_io_resources(io_resource *resources, io_resource_handle *handles)
{
io_resource *resource;
io_resource_handle *handle, *handle2;
status_t res = B_OK;
for (resource = resources, handle = handles;
resource->type != 0; ++resource, ++handle) {
res = acquire_io_resource(resource, handle);
if (res != B_OK)
break;
}
if (res != B_OK)
goto err;
*handle++ = NULL;
return B_OK;
err:
// collision detected: free all previously acquired resources
for (handle2 = handle; handle2 != handle; ++handle2)
release_io_resource(*handle2);
return res;
}
/** Acquire I/O resources.
* gNodeLock must be held.
*/
static status_t
acquire_io_resources(io_resource *resources, io_resource_handle *handles)
{
// try allocation until we either got all resources or
// detected a collision with a loaded device node
while (true) {
status_t res;
// allocate all resources
res = try_acquire_io_resources( resources, handles );
if (res == B_OK)
return B_OK;
if (res == B_WOULD_BLOCK) {
// collision with temporary allocation:
// wait until some resource is freed or blocked forever
// by a loaded driver
wait_for_resources();
} else {
// collided with loaded node - no point waiting for the node
TRACE(("acquire_io_resouces(): Collision with loaded device node\n"));
return res;
}
}
}
/** Unregister devices that collide with one of our I/O resources */
static void
unregister_colliding_nodes(const io_resource_handle *resources)
{
const io_resource_handle *resource;
for (resource = resources; *resource != NULL; ++resource) {
switch ((*resource)->resource.type) {
case IO_MEM:
unregister_colliding_node_range(io_mem_list, *resource);
break;
case IO_PORT:
unregister_colliding_node_range(io_port_list, *resource);
break;
case ISA_DMA_CHANNEL:
unregister_colliding_node_range(isa_dma_list, *resource);
break;
}
}
}
/** Unregister device nodes that collide with I/O resource */
static void
unregister_colliding_node_range(io_resource_info *list, io_resource_info *resource)
{
io_resource_info *cur;
uint32 base = resource->resource.base;
uint32 length = resource->resource.length;
do {
for (cur = list; cur != NULL; cur = cur->next) {
// ignore ourself
if (cur == resource)
continue;
// 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_handle owner = cur->owner;
if (owner == NULL)
panic("Transfer of I/O resources from temporary to device node collided with other temporary allocation");
TRACE(("Deleting colliding device node %p\n", owner));
// make sure node still exists after we'll have released lock
++owner->ref_count;
// we have to release lock during unregistration
benaphore_unlock(&gNodeLock);
// unregister device node - we own its resources now
// (its resources are freed by the next remove_node_ref call)
dm_unregister_node(owner);
benaphore_lock(&gNodeLock);
dm_put_node_nolock(owner);
// restart loop as resource list may have changed meanwhile
break;
}
}
} while (cur != NULL);
}
/** Unblock other temporary allocations so they can retry.
* gNodeLock must be held.
*/
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
dm_assign_io_resources(device_node_info *node, const io_resource_handle *resources)
{
io_resource_handle *resource;
if (resources == NULL)
return;
unregister_colliding_nodes(resources);
memcpy(node->io_resources, resources,
(node->num_io_resources + 1) * sizeof(io_resource_handle));
benaphore_lock(&gNodeLock);
for (resource = node->io_resources; *resource != NULL; ++resource) {
(*resource)->owner = node;
}
// as the resources were only temporary previously, other temporary
// allocations may be waiting for us; time to wake them, so they can
// give up
unblock_temporary_allocation();
benaphore_unlock(&gNodeLock);
}
/** 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 held.
*/
void
dm_release_node_resources(device_node_info *node)
{
io_resource_handle *resource;
if (*node->io_resources != NULL)
TRACE(("freeing I/O resources of node %p\n", node));
for (resource = node->io_resources; *resource != NULL; ++resource) {
// set owner to NULL as we don't want to resource anymore
(*resource)->owner = NULL;
release_io_resource(*resource);
}
// make sure we won't release resources twice
*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 status;
TRACE(("dm_acquire_io_resources()\n"));
benaphore_lock(&gNodeLock);
status = acquire_io_resources(resources, handles);
benaphore_unlock(&gNodeLock);
TRACE((" done (%s)\n", strerror(status)));
return status;
}
/** 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;
}
@@ -0,0 +1,151 @@
/*
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include "io_resources.h"
#include <stdlib.h>
#include <string.h>
//#define TRACE_IO_RESOURCES
#ifdef TRACE_IO_RESOURCES
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
typedef DoublyLinkedList<io_resource_private,
DoublyLinkedListMemberGetLink<io_resource_private,
&io_resource_private::fTypeLink> > ResourceTypeList;
static ResourceTypeList sMemoryList;
static ResourceTypeList sPortList;
static ResourceTypeList sDMAChannelList;
io_resource_private::io_resource_private()
{
_Init();
}
io_resource_private::~io_resource_private()
{
Release();
}
void
io_resource_private::_Init()
{
type = 0;
base = 0;
length = 0;
}
status_t
io_resource_private::Acquire(const io_resource& resource)
{
if (!_IsValid(resource))
return B_BAD_VALUE;
type = resource.type;
base = resource.base;
if (type != B_ISA_DMA_CHANNEL)
length = resource.length;
else
length = 1;
ResourceTypeList* list = NULL;
switch (type) {
case B_IO_MEMORY:
list = &sMemoryList;
break;
case B_IO_PORT:
list = &sPortList;
break;
case B_ISA_DMA_CHANNEL:
list = &sDMAChannelList;
break;
}
ResourceTypeList::Iterator iterator = list->GetIterator();
while (iterator.HasNext()) {
io_resource* resource = iterator.Next();
// we need the "base + length - 1" trick to avoid wrap around at 4 GB
if (resource->base >= base
&& resource->base + length - 1 <= base + length - 1) {
// This range is already covered by someone else
// TODO: we might want to ignore resources that belong to
// a node that isn't used.
return B_RESOURCE_UNAVAILABLE;
}
}
list->Add(this);
return B_OK;
}
void
io_resource_private::Release()
{
if (type == 0)
return;
switch (type) {
case B_IO_MEMORY:
sMemoryList.Remove(this);
break;
case B_IO_PORT:
sPortList.Remove(this);
break;
case B_ISA_DMA_CHANNEL:
sDMAChannelList.Remove(this);
break;
}
_Init();
}
/*static*/ bool
io_resource_private::_IsValid(const io_resource& resource)
{
switch (resource.type) {
case B_IO_MEMORY:
return resource.base + resource.length > resource.base;
case B_IO_PORT:
return (uint16)resource.base == resource.base
&& (uint16)resource.length == resource.length
&& resource.base + resource.length > resource.base;
case B_ISA_DMA_CHANNEL:
return resource.base <= 8;
default:
return false;
}
}
// #pragma mark -
void
dm_init_io_resources(void)
{
new(&sMemoryList) ResourceTypeList;
new(&sPortList) ResourceTypeList;
new(&sDMAChannelList) ResourceTypeList;
}
@@ -0,0 +1,45 @@
/*
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#ifndef IO_RESOURCES_H
#define IO_RESOURCES_H
#include <device_manager.h>
#include <util/DoublyLinkedList.h>
struct io_resource_private : io_resource,
DoublyLinkedListLinkImpl<io_resource_private> {
io_resource_private();
~io_resource_private();
status_t Acquire(const io_resource& resource);
void Release();
private:
void _Init();
static bool _IsValid(const io_resource& resource);
public:
DoublyLinkedListLink<io_resource_private> fTypeLink;
};
typedef DoublyLinkedList<io_resource_private> ResourceList;
#ifdef __cplusplus
extern "C" {
#endif
void dm_init_io_resources(void);
#ifdef __cplusplus
}
#endif
#endif /* IO_RESOURCES_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/*
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef LEGACY_DRIVERS_H
#define LEGACY_DRIVERS_H
#include <Drivers.h>
#ifdef __cplusplus
extern "C" {
#endif
status_t legacy_driver_add(const char* path);
status_t legacy_driver_publish(const char* path, device_hooks* hooks);
status_t legacy_driver_rescan(const char* driverName);
status_t legacy_driver_probe(const char* path);
status_t legacy_driver_init(void);
#ifdef __cplusplus
}
#endif
#endif // LEGACY_DRIVERS_H
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -5,8 +5,7 @@ UsePrivateHeaders [ FDirName kernel fs ] ;
UsePrivateHeaders [ FDirName kernel util ] ;
UsePrivateHeaders net shared storage ;
KernelMergeObject kernel_fs.o :
devfs.cpp
KernelMergeObject kernel_fs.o :
fd.cpp
fifo.cpp
IOScheduler.cpp
+3 -3
View File
@@ -275,7 +275,7 @@ main2(void *unused)
device_manager_init(&sKernelArgs);
TRACE("Add preloaded old-style drivers\n");
devfs_add_preloaded_drivers(&sKernelArgs);
legacy_driver_add_preloaded(&sKernelArgs);
int_init_post_device_manager(&sKernelArgs);
@@ -308,14 +308,14 @@ main2(void *unused)
status_t status = find_directory(B_BEOS_SYSTEM_DIRECTORY, gBootDevice,
false, bootScriptPath.LockBuffer(), bootScriptPath.BufferSize());
if (status != B_OK)
dprintf("main2: find_directory() failed: %s\n", strerror(status));
dprintf("main2: find_directory() failed: %s\n", strerror(status));
bootScriptPath.UnlockBuffer();
status = bootScriptPath.Append("boot/Bootscript");
if (status != B_OK) {
dprintf("main2: constructing path to Bootscript failed: "
"%s\n", strerror(status));
}
const char *args[] = { "/bin/sh", bootScriptPath.Path(), NULL };
int32 argc = 2;
thread_id thread;
+7 -9
View File
@@ -45,7 +45,6 @@
*/
extern module_info gDeviceManagerModule;
extern module_info gDeviceRootModule;
extern module_info gDeviceForDriversModule;
extern module_info gFrameBufferConsoleModule;
// file systems
@@ -55,7 +54,6 @@ extern module_info gDeviceFileSystem;
static module_info *sBuiltInModules[] = {
&gDeviceManagerModule,
&gDeviceRootModule,
&gDeviceForDriversModule,
&gFrameBufferConsoleModule,
&gRootFileSystem,
@@ -144,7 +142,7 @@ static bool sDisableUserAddOns = false;
* they have to wait for each other, i.e. we need one lock per module;
* also we must detect circular references during init and not dead-lock
*/
static recursive_lock sModulesLock;
static recursive_lock sModulesLock;
/* These are the standard base paths where we start to look for modules
* to load. Order is important, the last entry here will be searched
@@ -176,7 +174,7 @@ module_hash(void *_module, const void *_key, uint32 range)
if (module != NULL)
return hash_hash_string(module->name) % range;
if (name != NULL)
return hash_hash_string(name) % range;
@@ -655,8 +653,8 @@ uninit_module(module *module)
return status;
}
default:
return B_ERROR;
default:
return B_ERROR;
}
// never trespasses here
}
@@ -761,7 +759,7 @@ iterator_get_next_module(module_iterator *iterator, char *buffer,
recursive_lock_unlock(&sModulesLock);
// prevent from falling into modules hash iteration again
iterator->loaded_modules = false;
iterator->loaded_modules = false;
}
nextPath:
@@ -1006,7 +1004,7 @@ register_preloaded_module_image(struct preloaded_image *image)
error:
free(moduleImage);
// We don't need this image anymore. We keep it, if it doesn't look like
// a module at all. It might be an old-style driver.
if (image->is_module)
@@ -1309,7 +1307,7 @@ read_next_module_name(void *cookie, char *buffer, size_t *_bufferSize)
iterate through all modules that are currently loaded; have a valid
module_image pointer, which would be hard to test for)
*/
status_t
status_t
get_next_loaded_module_name(uint32 *_cookie, char *buffer, size_t *_bufferSize)
{
if (sModulesHash == NULL) {