* 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:
@@ -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 ;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ;)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
+6
-5
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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, ¶ms.alignment, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_ALIGNMENT, ¶ms.alignment, true) != B_OK)
|
||||
params.alignment = 0;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, ¶ms.max_blocks, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_BLOCKS_ITEM, ¶ms.max_blocks, true) != B_OK)
|
||||
params.max_blocks = 0xffffffff;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_DMA_BOUNDARY, ¶ms.dma_boundary, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_DMA_BOUNDARY, ¶ms.dma_boundary, true) != B_OK)
|
||||
params.dma_boundary = ~0;
|
||||
if (pnp->get_attr_uint32(node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, ¶ms.max_sg_block_size, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCK_SIZE, ¶ms.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, ¶ms.max_sg_blocks, true) != B_OK)
|
||||
if (pnp->get_attr_uint32(data->node, B_BLOCK_DEVICE_MAX_SG_BLOCKS, ¶ms.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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
+87
-88
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user