diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 0905a5d76d..d6476777e4 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -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 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)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 = hostname ; diff --git a/headers/os/drivers/block_io.h b/headers/os/drivers/block_io.h index c9e5eaa4f7..a689df63a2 100644 --- a/headers/os/drivers/block_io.h +++ b/headers/os/drivers/block_io.h @@ -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; diff --git a/headers/os/drivers/bus/IDE.h b/headers/os/drivers/bus/IDE.h index 050b5c02a1..ff74da90ce 100644 --- a/headers/os/drivers/bus/IDE.h +++ b/headers/os/drivers/bus/IDE.h @@ -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 + #include #include @@ -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__ */ diff --git a/headers/os/drivers/bus/ISA.h b/headers/os/drivers/bus/ISA.h index f6ba5ddfe1..54d3f960aa 100644 --- a/headers/os/drivers/bus/ISA.h +++ b/headers/os/drivers/bus/ISA.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 #include -// 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 */ diff --git a/headers/os/drivers/bus/PCI.h b/headers/os/drivers/bus/PCI.h index 7832076667..fa362c7bc7 100644 --- a/headers/os/drivers/bus/PCI.h +++ b/headers/os/drivers/bus/PCI.h @@ -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 #include -// 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 */ diff --git a/headers/os/drivers/bus/SCSI.h b/headers/os/drivers/bus/SCSI.h index 49814de8c5..4ac3022e07 100644 --- a/headers/os/drivers/bus/SCSI.h +++ b/headers/os/drivers/bus/SCSI.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 of CCB (in which case it must be continuous), or store a pointer to a S/G list that contains physical addresses in - /. If is non-Null, 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 + /. If is non-Null, 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 must be locked, but doesn't need to be. - You can either execute the request synchronously ("sync_io") or - asynchronously ("async_io"; you have to acquire to find - out when the request is finished). In the first case you can use either - or , in the latter only. + You can either execute the request synchronously ("sync_io") or + asynchronously ("async_io"; you have to acquire to find + out when the request is finished). In the first case you can use either + or , in the latter 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 @@ is a safe bet. - For SIM writers: + For SIM writers: Requests sent by peripheral drivers are forwarded to the 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 () 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 () 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 () for the bus. The device limit is + path_inquiry () for the bus. The device limit is determined via INQUIRY. If you need a lower/dynamic limit, you can refuse a request by . If is true, no further requests to the bus will be sent, if is false, no further requests to the device will be sent. To terminate the overflow condition, call /. It also terminated when a request for the bus/device is finished via or . - Because of the asynchronous nature, requests may still arrive after the - overflow condition being signalled, so you should add a safety test to - . + Because of the asynchronous nature, requests may still arrive after the + overflow condition being signalled, so you should add a safety test to + . If a problem occurs during execution, you can ask for a restart via . 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 is SCSI_REQ_CMP_ERR and is + SCSI bus manager can emulate auto-sense by executing a REQUEST SENSE + if is SCSI_REQ_CMP_ERR and 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 diff --git a/headers/os/drivers/device_manager.h b/headers/os/drivers/device_manager.h index 4df541a108..67b3ec13a6 100644 --- a/headers/os/drivers/device_manager.h +++ b/headers/os/drivers/device_manager.h @@ -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 -// 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 */ diff --git a/headers/private/drivers/fast_log.h b/headers/private/drivers/fast_log.h deleted file mode 100644 index 310a758e95..0000000000 --- a/headers/private/drivers/fast_log.h +++ /dev/null @@ -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 - -// 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 diff --git a/headers/private/drivers/ide_adapter.h b/headers/private/drivers/ide_adapter.h index 9beb632691..fea3435c62 100644 --- a/headers/private/drivers/ide_adapter.h +++ b/headers/private/drivers/ide_adapter.h @@ -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, diff --git a/headers/private/drivers/scsi_periph.h b/headers/private/drivers/scsi_periph.h index 9570f68dd4..e0fd2b402b 100644 --- a/headers/private/drivers/scsi_periph.h +++ b/headers/private/drivers/scsi_periph.h @@ -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" diff --git a/headers/private/kernel/fs/devfs.h b/headers/private/kernel/fs/devfs.h index fd8f2e7e0f..f5aad502d4 100644 --- a/headers/private/kernel/fs/devfs.h +++ b/headers/private/kernel/fs/devfs.h @@ -11,20 +11,11 @@ #include -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); diff --git a/headers/private/kernel/kdevice_manager.h b/headers/private/kernel/kdevice_manager.h index f4851336d2..9113773930 100644 --- a/headers/private/kernel/kdevice_manager.h +++ b/headers/private/kernel/kdevice_manager.h @@ -1,85 +1,28 @@ /* - * 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. * Distributed under the terms of the MIT License. */ #ifndef _KERNEL_DEVICE_MANAGER_H #define _KERNEL_DEVICE_MANAGER_H -#include #include -#include - - -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 */ diff --git a/headers/private/system/device_manager_defs.h b/headers/private/system/device_manager_defs.h new file mode 100644 index 0000000000..24a76b52c8 --- /dev/null +++ b/headers/private/system/device_manager_defs.h @@ -0,0 +1,38 @@ +/* + * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SYSTEM_DEVICE_MANAGER_DEFS_H +#define _SYSTEM_DEVICE_MANAGER_DEFS_H + + +#include + + +// 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 */ diff --git a/src/add-ons/kernel/bus_managers/ide/basic_protocol.c b/src/add-ons/kernel/bus_managers/ide/basic_protocol.c index 5a49725c69..4b248893ea 100644 --- a/src/add-ons/kernel/bus_managers/ide/basic_protocol.c +++ b/src/add-ons/kernel/bus_managers/ide/basic_protocol.c @@ -53,7 +53,7 @@ wait_for_drdy(ide_device_info *device) } -/** reset entire IDE bus +/** reset entire IDE bus * all active request apart from 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 ;) diff --git a/src/add-ons/kernel/bus_managers/ide/channels.c b/src/add-ons/kernel/bus_managers/ide/channels.c index 941647f33d..746a003963 100644 --- a/src/add-ons/kernel/bus_managers/ide/channels.c +++ b/src/add-ons/kernel/bus_managers/ide/channels.c @@ -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; } diff --git a/src/add-ons/kernel/bus_managers/ide/ide_internal.h b/src/add-ons/kernel/bus_managers/ide/ide_internal.h index 1dfb0b8454..30042e397d 100644 --- a/src/add-ons/kernel/bus_managers/ide/ide_internal.h +++ b/src/add-ons/kernel/bus_managers/ide/ide_internal.h @@ -5,19 +5,12 @@ #ifndef __IDE_INTERNAL_H__ #define __IDE_INTERNAL_H__ -/* - Part of Open IDE bus manager - - Internal structures -*/ - #include #include #include "ide_device_infoblock.h" #include #include -#include #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); diff --git a/src/add-ons/kernel/bus_managers/ide/ide_sim.c b/src/add-ons/kernel/bus_managers/ide/ide_sim.c index 55dee3956e..8ada3b5b20 100644 --- a/src/add-ons/kernel/bus_managers/ide/ide_sim.c +++ b/src/add-ons/kernel/bus_managers/ide/ide_sim.c @@ -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 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, diff --git a/src/add-ons/kernel/bus_managers/ide/sync.c b/src/add-ons/kernel/bus_managers/ide/sync.c index e86f0504ae..ea93af5d54 100644 --- a/src/add-ons/kernel/bus_managers/ide/sync.c +++ b/src/add-ons/kernel/bus_managers/ide/sync.c @@ -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 } } diff --git a/src/add-ons/kernel/bus_managers/isa/isa.c b/src/add-ons/kernel/bus_managers/isa/isa.c index 87985b7563..d789d8badb 100644 --- a/src/add-ons/kernel/bus_managers/isa/isa.c +++ b/src/add-ons/kernel/bus_managers/isa/isa.c @@ -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 }; diff --git a/src/add-ons/kernel/bus_managers/pci/Jamfile b/src/add-ons/kernel/bus_managers/pci/Jamfile index 971d7235fd..d94b91d876 100644 --- a/src/add-ons/kernel/bus_managers/pci/Jamfile +++ b/src/add-ons/kernel/bus_managers/pci/Jamfile @@ -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 ] ; diff --git a/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_controller.cpp b/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_controller.cpp index 79dce06868..7194886014 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_controller.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_controller.cpp @@ -1,12 +1,22 @@ +/* + * Copyright 2007, François Revol . + * Distributed under the terms of the MIT License. + */ + + #include "pci_controller.h" #include -#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" diff --git a/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_io.c b/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_io.c index 8405007e07..4a4a8f410f 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_io.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/m68k/pci_io.c @@ -1,6 +1,13 @@ +/* + * Copyright 2007, François Revol . + * Distributed under the terms of the MIT License. + */ + + #include "pci_io.h" #include "pci_priv.h" + status_t pci_io_init() { diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp index 9e5e9df656..8c0a6cd075 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_controller.cpp @@ -1,8 +1,14 @@ +/* + * Copyright 2006, Ingo Weinhold. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + #include "pci_controller.h" #include -#include "pci_priv.h" +#include "pci_private.h" #include "openfirmware/pci_openfirmware.h" diff --git a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c index 4abb2fd8b3..6202b911c3 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/ppc/pci_io.c @@ -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() diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c index dfd6dc9e3d..1852f70f3b 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_bios.c @@ -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; } diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c index 914286be8b..cd1797d4b2 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_controller.c @@ -1,13 +1,12 @@ /* * Copyright 2006, Marcus Overhagen. All rights reserved. - * * Distributed under the terms of the MIT License. */ #include #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; } diff --git a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_io.c b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_io.c index 4db712fe58..e62f9a2c4a 100644 --- a/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_io.c +++ b/src/add-ons/kernel/bus_managers/pci/arch/x86/pci_io.c @@ -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() { diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index 0ad527053e..79df9cd80b 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -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) diff --git a/src/add-ons/kernel/bus_managers/pci/pci_device.c b/src/add-ons/kernel/bus_managers/pci/pci_device.c deleted file mode 100644 index 74cc1f24af..0000000000 --- a/src/add-ons/kernel/bus_managers/pci/pci_device.c +++ /dev/null @@ -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 -#include -#include - -#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 -}; diff --git a/src/add-ons/kernel/bus_managers/pci/pci_device.cpp b/src/add-ons/kernel/bus_managers/pci/pci_device.cpp new file mode 100644 index 0000000000..fe795fdaad --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/pci_device.cpp @@ -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 +#include +#include + +#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 +}; diff --git a/src/add-ons/kernel/bus_managers/pci/pci_info.cpp b/src/add-ons/kernel/bus_managers/pci/pci_info.cpp index 254d06d1e8..af667e6642 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_info.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci_info.cpp @@ -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 @@ -9,7 +9,7 @@ #include #include #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); diff --git a/src/add-ons/kernel/bus_managers/pci/pci_module.c b/src/add-ons/kernel/bus_managers/pci/pci_module.c index b978decde5..8ce36d3806 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_module.c +++ b/src/add-ons/kernel/bus_managers/pci/pci_module.c @@ -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 -#include -#include #include -#include -#include - -#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 }; diff --git a/src/add-ons/kernel/bus_managers/pci/pci_priv.h b/src/add-ons/kernel/bus_managers/pci/pci_private.h similarity index 83% rename from src/add-ons/kernel/bus_managers/pci/pci_priv.h rename to src/add-ons/kernel/bus_managers/pci/pci_private.h index 97b4149725..8633e28ea3 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_priv.h +++ b/src/add-ons/kernel/bus_managers/pci/pci_private.h @@ -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; diff --git a/src/add-ons/kernel/bus_managers/pci/pci_root.cpp b/src/add-ons/kernel/bus_managers/pci/pci_root.cpp new file mode 100644 index 0000000000..06c475dbaf --- /dev/null +++ b/src/add-ons/kernel/bus_managers/pci/pci_root.cpp @@ -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 +#include + +#include + +#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 +}; diff --git a/src/add-ons/kernel/bus_managers/scsi/bus_raw.c b/src/add-ons/kernel/bus_managers/scsi/bus_raw.c index 7aff64b57d..c81ab64cb5 100644 --- a/src/add-ons/kernel/bus_managers/scsi/bus_raw.c +++ b/src/add-ons/kernel/bus_managers/scsi/bus_raw.c @@ -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 -#include #include #include #include +#include + // 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 }; diff --git a/src/add-ons/kernel/bus_managers/scsi/busses.c b/src/add-ons/kernel/bus_managers/scsi/busses.c index d0fed5cc8e..41c29ba45a 100644 --- a/src/add-ons/kernel/bus_managers/scsi/busses.c +++ b/src/add-ons/kernel/bus_managers/scsi/busses.c @@ -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 }, diff --git a/src/add-ons/kernel/bus_managers/scsi/device_scan.c b/src/add-ons/kernel/bus_managers/scsi/device_scan.c index 0ef7abd3f0..7f2b60ac17 100644 --- a/src/add-ons/kernel/bus_managers/scsi/device_scan.c +++ b/src/add-ons/kernel/bus_managers/scsi/device_scan.c @@ -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) diff --git a/src/add-ons/kernel/bus_managers/scsi/devices.c b/src/add-ons/kernel/bus_managers/scsi/devices.c index 6b256ecb2d..65e9cd2f22 100644 --- a/src/add-ons/kernel/bus_managers/scsi/devices.c +++ b/src/add-ons/kernel/bus_managers/scsi/devices.c @@ -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 -#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, diff --git a/src/add-ons/kernel/bus_managers/scsi/emulation.c b/src/add-ons/kernel/bus_managers/scsi/emulation.c index 37e2cc1fcc..c58fc7b367 100644 --- a/src/add-ons/kernel/bus_managers/scsi/emulation.c +++ b/src/add-ons/kernel/bus_managers/scsi/emulation.c @@ -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; } diff --git a/src/add-ons/kernel/bus_managers/scsi/scsi.c b/src/add-ons/kernel/bus_managers/scsi/scsi.c index 51ff3a0d7e..132cafe881 100644 --- a/src/add-ons/kernel/bus_managers/scsi/scsi.c +++ b/src/add-ons/kernel/bus_managers/scsi/scsi.c @@ -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 @@ -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 }; diff --git a/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h b/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h index 48e7c649b6..be2f3ac3df 100644 --- a/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h +++ b/src/add-ons/kernel/bus_managers/scsi/scsi_internal.h @@ -12,33 +12,14 @@ #include #include #include -#include -#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; diff --git a/src/add-ons/kernel/bus_managers/scsi/scsi_io.c b/src/add-ons/kernel/bus_managers/scsi/scsi_io.c index 49aa2850a2..ed8cf59883 100644 --- a/src/add-ons/kernel/bus_managers/scsi/scsi_io.c +++ b/src/add-ons/kernel/bus_managers/scsi/scsi_io.c @@ -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); diff --git a/src/add-ons/kernel/bus_managers/scsi/sim_interface.c b/src/add-ons/kernel/bus_managers/scsi/sim_interface.c index 1cf0b6da93..f431199888 100644 --- a/src/add-ons/kernel/bus_managers/scsi/sim_interface.c +++ b/src/add-ons/kernel/bus_managers/scsi/sim_interface.c @@ -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 #include #include /** 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, diff --git a/src/add-ons/kernel/bus_managers/scsi/wrapper.h b/src/add-ons/kernel/bus_managers/scsi/wrapper.h index 3248124820..f027ff2ca3 100644 --- a/src/add-ons/kernel/bus_managers/scsi/wrapper.h +++ b/src/add-ons/kernel/bus_managers/scsi/wrapper.h @@ -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 diff --git a/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c b/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c index 600d209e4d..80a023bb64 100644 --- a/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c +++ b/src/add-ons/kernel/busses/ide/generic_ide_pci/generic_ide_pci.c @@ -23,7 +23,7 @@ #include "wrapper.h" -#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/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[] = { diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci.c b/src/add-ons/kernel/busses/scsi/ahci/ahci.c index a85393d0f9..f32ca614c8 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci.c +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci.c @@ -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 }, {} }; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp index 8ec84c017c..319449b4f0 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.cpp @@ -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) diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h index 6bcadcc698..ebf9fc4ef3 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_controller.h @@ -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; diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp index 9bf2ad76be..b2b0ac32df 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_sim.cpp @@ -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(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(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 }; - diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/device.c b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/device.c index 98f0c65b45..dececeb621 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/device.c +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/device.c @@ -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; } diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/handle.c b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/handle.c index eaff182d23..2f912ec967 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/handle.c +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/handle.c @@ -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; } diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.c b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.c index 009ec5437d..6e8d0e003a 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.c +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.c @@ -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 diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.h b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.h index ac7ef62b33..b48d27e404 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.h +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk.h @@ -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 -#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 */ diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk_int.h b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk_int.h index 75f7dcf423..374ec3bd58 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk_int.h +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_dsk/scsi_dsk_int.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); diff --git a/src/add-ons/kernel/generic/Jamfile b/src/add-ons/kernel/generic/Jamfile index f393d9fbae..617d177eaf 100644 --- a/src/add-ons/kernel/generic/Jamfile +++ b/src/add-ons/kernel/generic/Jamfile @@ -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 ; diff --git a/src/add-ons/kernel/generic/block_io/block_io.c b/src/add-ons/kernel/generic/block_io/block_io.c index 50395f51cc..6e8fe31614 100644 --- a/src/add-ons/kernel/generic/block_io/block_io.c +++ b/src/add-ons/kernel/generic/block_io/block_io.c @@ -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 @@ -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 }; diff --git a/src/add-ons/kernel/generic/block_io/block_io_private.h b/src/add-ons/kernel/generic/block_io/block_io_private.h index 3eb1ee94dc..6221e6ecb4 100644 --- a/src/add-ons/kernel/generic/block_io/block_io_private.h +++ b/src/add-ons/kernel/generic/block_io/block_io_private.h @@ -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); diff --git a/src/add-ons/kernel/generic/fast_log/Jamfile b/src/add-ons/kernel/generic/fast_log/Jamfile deleted file mode 100644 index c8124fbe11..0000000000 --- a/src/add-ons/kernel/generic/fast_log/Jamfile +++ /dev/null @@ -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 - ; - diff --git a/src/add-ons/kernel/generic/fast_log/clients.c b/src/add-ons/kernel/generic/fast_log/clients.c deleted file mode 100644 index 2d2bd9abc7..0000000000 --- a/src/add-ons/kernel/generic/fast_log/clients.c +++ /dev/null @@ -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 -#include - -#include -#include - - -// 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(" 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("\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( "\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 -}; diff --git a/src/add-ons/kernel/generic/fast_log/device.c b/src/add-ons/kernel/generic/fast_log/device.c deleted file mode 100644 index 174b20dd1e..0000000000 --- a/src/add-ons/kernel/generic/fast_log/device.c +++ /dev/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 -#include - - -// 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; -} diff --git a/src/add-ons/kernel/generic/fast_log/dl_list.h b/src/add-ons/kernel/generic/fast_log/dl_list.h deleted file mode 100644 index 36a0d22da9..0000000000 --- a/src/add-ons/kernel/generic/fast_log/dl_list.h +++ /dev/null @@ -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 diff --git a/src/add-ons/kernel/generic/fast_log/fast_log_int.h b/src/add-ons/kernel/generic/fast_log/fast_log_int.h deleted file mode 100644 index 0a573e9073..0000000000 --- a/src/add-ons/kernel/generic/fast_log/fast_log_int.h +++ /dev/null @@ -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 -#include -#include -#include - -// 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; diff --git a/src/add-ons/kernel/generic/fast_log/long_buffers.c b/src/add-ons/kernel/generic/fast_log/long_buffers.c deleted file mode 100644 index 8681cb7a71..0000000000 --- a/src/add-ons/kernel/generic/fast_log/long_buffers.c +++ /dev/null @@ -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 - -#include - - -// 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("\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; -} - diff --git a/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c b/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c index c8eef8f3e5..6ffd54b4b1 100644 --- a/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c +++ b/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c @@ -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, diff --git a/src/add-ons/kernel/generic/scsi_periph/device.c b/src/add-ons/kernel/generic/scsi_periph/device.c index 36da090ba2..743cda3d47 100644 --- a/src/add-ons/kernel/generic/scsi_periph/device.c +++ b/src/add-ons/kernel/generic/scsi_periph/device.c @@ -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; diff --git a/src/add-ons/kernel/generic/scsi_periph/io.c b/src/add-ons/kernel/generic/scsi_periph/io.c index dff7645662..50c3f41173 100644 --- a/src/add-ons/kernel/generic/scsi_periph/io.c +++ b/src/add-ons/kernel/generic/scsi_periph/io.c @@ -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)); } diff --git a/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h b/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h index 7e063fd85c..473eeaa4a0 100644 --- a/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h +++ b/src/add-ons/kernel/generic/scsi_periph/scsi_periph_int.h @@ -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, diff --git a/src/system/kernel/device_manager/BaseDevice.cpp b/src/system/kernel/device_manager/BaseDevice.cpp new file mode 100644 index 0000000000..32e1467536 --- /dev/null +++ b/src/system/kernel/device_manager/BaseDevice.cpp @@ -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() +{ +} diff --git a/src/system/kernel/device_manager/BaseDevice.h b/src/system/kernel/device_manager/BaseDevice.h new file mode 100644 index 0000000000..96c0389ea2 --- /dev/null +++ b/src/system/kernel/device_manager/BaseDevice.h @@ -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 + + +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 diff --git a/src/system/kernel/device_manager/Jamfile b/src/system/kernel/device_manager/Jamfile index 4797f31e6a..3596506d09 100644 --- a/src/system/kernel/device_manager/Jamfile +++ b/src/system/kernel/device_manager/Jamfile @@ -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 diff --git a/src/system/kernel/fs/devfs.cpp b/src/system/kernel/device_manager/devfs.cpp similarity index 55% rename from src/system/kernel/fs/devfs.cpp rename to src/system/kernel/device_manager/devfs.cpp index b684dec97f..1f498bd20b 100644 --- a/src/system/kernel/fs/devfs.cpp +++ b/src/system/kernel/device_manager/devfs.cpp @@ -7,7 +7,7 @@ */ -#include +#include #include #include @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -26,20 +25,22 @@ #include #include #include +#include +#include #include -#include #include -#include #include #include #include #include #include -#include "IOScheduler.h" +#include "BaseDevice.h" +#include "../fs/IOScheduler.h" +#include "legacy_drivers.h" -//#define TRACE_DEVFS +#define TRACE_DEVFS #ifdef TRACE_DEVFS # define TRACE(x) dprintf x #else @@ -48,7 +49,7 @@ struct devfs_partition { - struct devfs_vnode *raw_device; + struct devfs_vnode* raw_device; partition_info info; }; @@ -61,61 +62,57 @@ enum { }; struct devfs_stream { - mode_t type; + mode_t type; union { struct stream_dir { - struct devfs_vnode *dir_head; + struct devfs_vnode* dir_head; struct list cookies; int32 scanned; } dir; struct stream_dev { - device_node_info *node; - pnp_devfs_driver_info *info; - device_hooks *ops; - struct devfs_partition *partition; - IOScheduler *scheduler; - driver_entry *driver; + BaseDevice* device; + struct devfs_partition* partition; + IOScheduler* scheduler; } dev; struct stream_symlink { - const char *path; + const char* path; size_t length; } symlink; } u; }; struct devfs_vnode { - struct devfs_vnode *all_next; - ino_t id; - char *name; - time_t modification_time; - time_t creation_time; - uid_t uid; - gid_t gid; - struct devfs_vnode *parent; - struct devfs_vnode *dir_next; - struct devfs_stream stream; + struct devfs_vnode* all_next; + ino_t id; + char* name; + time_t modification_time; + time_t creation_time; + uid_t uid; + gid_t gid; + struct devfs_vnode* parent; + struct devfs_vnode* dir_next; + struct devfs_stream stream; }; #define DEVFS_HASH_SIZE 16 struct devfs { dev_t id; - fs_volume *volume; + fs_volume* volume; recursive_lock lock; - int32 next_vnode_id; - hash_table *vnode_hash; - struct devfs_vnode *root_vnode; - hash_table *driver_hash; + int32 next_vnode_id; + hash_table* vnode_hash; + struct devfs_vnode* root_vnode; }; struct devfs_dir_cookie { - struct list_link link; - struct devfs_vnode *current; - int32 state; // iteration state + struct list_link link; + struct devfs_vnode* current; + int32 state; // iteration state }; struct devfs_cookie { - void *device_cookie; + void* device_cookie; }; // directory iteration states @@ -126,40 +123,6 @@ enum { ITERATION_STATE_BEGIN = ITERATION_STATE_DOT, }; -struct driver_entry { - driver_entry *next; - const char *path; - const char *name; - dev_t device; - ino_t node; - time_t last_modified; - image_id image; - uint32 devices_published; - uint32 devices_used; - bool binary_updated; - int32 priority; - - // driver image information - int32 api_version; - device_hooks *(*find_device)(const char *); - const char **(*publish_devices)(void); - status_t (*uninit_driver)(void); - status_t (*uninit_hardware)(void); -}; - -struct path_entry : DoublyLinkedListLinkImpl { - char path[B_PATH_NAME_LENGTH]; -}; - -class DriverWatcher : public NotificationListener { - public: - DriverWatcher(); - virtual ~DriverWatcher(); - - virtual void EventOccured(NotificationService& service, - const KMessage* event); -}; - // extern and in a private namespace only to make forward declaration possible namespace { extern fs_volume_ops kVolumeOps; @@ -174,470 +137,14 @@ static void get_device_name(struct devfs_vnode *vnode, char *buffer, static status_t unpublish_node(struct devfs *fs, devfs_vnode *node, mode_t type); static status_t publish_device(struct devfs *fs, const char *path, - device_node_info *deviceNode, pnp_devfs_driver_info *info, - driver_entry *driver, device_hooks *ops, int32 apiVersion); -static status_t unload_driver(driver_entry *driver); -static status_t load_driver(driver_entry *driver); + BaseDevice* device); /* the one and only allowed devfs instance */ -static struct devfs *sDeviceFileSystem = NULL; -static int32 sDefaultApiVersion = 1; -static DriverWatcher sDriverWatcher; -static int32 sDriverEvents; -static DoublyLinkedList sDriversToAdd; +static struct devfs* sDeviceFileSystem = NULL; -// #pragma mark - driver private - - -static uint32 -driver_entry_hash(void *_driver, const void *_key, uint32 range) -{ - driver_entry *driver = (driver_entry *)_driver; - const char *key = (const char *)_key; - - if (driver != NULL) - return hash_hash_string(driver->name) % range; - - return hash_hash_string(key) % range; -} - - -static int -driver_entry_compare(void *_driver, const void *_key) -{ - driver_entry *driver = (driver_entry *)_driver; - const char *key = (const char *)_key; - - return strcmp(driver->name, key); -} - - -/*! Collects all published devices of a driver, compares them to what the - driver would publish now, and then publishes/unpublishes the devices - as needed. - If the driver does not publish any devices anymore, it is unloaded. -*/ -static status_t -republish_driver(driver_entry *driver) -{ - if (driver->image < 0) { - // The driver is not yet loaded - go through the normal load procedure - return load_driver(driver); - } - - RecursiveLocker locker(&sDeviceFileSystem->lock); - - // build the list of currently present devices of this driver - // by iterating through all present nodes - struct hash_iterator i; - hash_open(sDeviceFileSystem->vnode_hash, &i); - - DoublyLinkedList currentNodes; - while (true) { - devfs_vnode *vnode = (devfs_vnode *)hash_next( - sDeviceFileSystem->vnode_hash, &i); - if (vnode == NULL) - break; - - if (S_ISCHR(vnode->stream.type) - && vnode->stream.u.dev.driver == driver) { - path_entry *entry = new(std::nothrow) path_entry; - if (entry == NULL) { - while ((entry = currentNodes.RemoveHead())) - delete entry; - hash_close(sDeviceFileSystem->vnode_hash, &i, false); - return B_NO_MEMORY; - } - - get_device_name(vnode, entry->path, sizeof(entry->path)); - currentNodes.Add(entry); - } - } - hash_close(sDeviceFileSystem->vnode_hash, &i, false); - - // now ask the driver for it's currently published devices - const char **devicePaths = driver->publish_devices(); - - int32 exported = 0; - for (; devicePaths != NULL && devicePaths[0]; devicePaths++) { - bool present = false; - path_entry *entry = currentNodes.Head(); - while (entry) { - if (strncmp(entry->path, devicePaths[0], B_PATH_NAME_LENGTH) == 0) { - // this device was present before and still is -> no republish - currentNodes.Remove(entry); - delete entry; - exported++; - present = true; - break; - } - - entry = currentNodes.GetNext(entry); - } - - device_hooks *hooks = driver->find_device(devicePaths[0]); - if (hooks == NULL) - continue; - - if (present) { - // update hooks - devfs_vnode *vnode; - status_t status = get_node_for_path(sDeviceFileSystem, - devicePaths[0], &vnode); - if (status != B_OK) - return status; - - vnode->stream.u.dev.ops = hooks; - continue; - } - - // the device was not present before -> publish it now - TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0])); - if (publish_device(sDeviceFileSystem, devicePaths[0], NULL, NULL, - driver, hooks, driver->api_version) == B_OK) - exported++; - } - - // what's left in currentNodes was present but is not anymore -> unpublish - path_entry *entry = currentNodes.Head(); - while (entry) { - TRACE(("devfs: unpublishing no more present \"%s\"\n", entry->path)); - devfs_unpublish_device(entry->path, true); - path_entry *next = currentNodes.GetNext(entry); - currentNodes.Remove(entry); - delete entry; - entry = next; - } - - if (exported == 0) { - TRACE(("devfs: driver \"%s\" does not publish any more nodes and is unloaded\n", driver->path)); - unload_driver(driver); - } - - return B_OK; -} - - -static status_t -load_driver(driver_entry *driver) -{ - status_t (*init_hardware)(void); - status_t (*init_driver)(void); - const char **devicePaths; - int32 exported = 0; - status_t status; - - driver->binary_updated = false; - - // load the module - image_id image = driver->image; - if (image < 0) { - image = load_kernel_add_on(driver->path); - if (image < 0) - return image; - } - - // For a valid device driver the following exports are required - - int32 *apiVersion; - if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, - (void **)&apiVersion) == B_OK) { -#if B_CUR_DRIVER_API_VERSION != 2 - // just in case someone decides to bump up the api version -#error Add checks here for new vs old api version! -#endif - if (*apiVersion > B_CUR_DRIVER_API_VERSION) { - dprintf("devfs: \"%s\" api_version %ld not handled\n", driver->name, - *apiVersion); - status = B_BAD_VALUE; - goto error1; - } - if (*apiVersion < 1) { - dprintf("devfs: \"%s\" api_version invalid\n", driver->name); - status = B_BAD_VALUE; - goto error1; - } - - driver->api_version = *apiVersion; - } else - dprintf("devfs: \"%s\" api_version missing\n", driver->name); - - if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, - (void **)&driver->publish_devices) != B_OK - || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, - (void **)&driver->find_device) != B_OK) { - dprintf("devfs: \"%s\" mandatory driver symbol(s) missing!\n", - driver->name); - status = B_BAD_VALUE; - goto error1; - } - - // Init the driver - - if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, - (void **)&init_hardware) == B_OK - && (status = init_hardware()) != B_OK) { - TRACE(("%s: init_hardware() failed: %s\n", driver->name, - strerror(status))); - status = ENXIO; - goto error1; - } - - if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, - (void **)&init_driver) == B_OK - && (status = init_driver()) != B_OK) { - TRACE(("%s: init_driver() failed: %s\n", driver->name, - strerror(status))); - status = ENXIO; - goto error2; - } - - // resolve and cache those for the driver unload code - if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT, - (void **)&driver->uninit_driver) != B_OK) - driver->uninit_driver = NULL; - if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, - (void **)&driver->uninit_hardware) != B_OK) - driver->uninit_hardware = NULL; - - // The driver has successfully been initialized, now we can - // finally publish its device entries - - driver->image = image; - return republish_driver(driver); - -error3: - if (driver->uninit_driver) - driver->uninit_driver(); - -error2: - if (driver->uninit_hardware) - driver->uninit_hardware(); - -error1: - if (driver->image < 0) { - unload_kernel_add_on(image); - driver->image = status; - } - - return status; -} - - -static status_t -unload_driver(driver_entry *driver) -{ - if (driver->image < 0) { - // driver is not currently loaded - return B_NO_INIT; - } - - if (driver->uninit_driver) - driver->uninit_driver(); - - if (driver->uninit_hardware) - driver->uninit_hardware(); - - unload_kernel_add_on(driver->image); - driver->image = -1; - driver->binary_updated = false; - driver->find_device = NULL; - driver->publish_devices = NULL; - driver->uninit_driver = NULL; - driver->uninit_hardware = NULL; - - return B_OK; -} - - -/*! Collects all devices belonging to the \a driver and unpublishs them. -*/ -static void -unpublish_driver(driver_entry *driver) -{ - RecursiveLocker locker(&sDeviceFileSystem->lock); - - // Iterate through all nodes until all devices of this driver have - // been unpublished - - while (driver->devices_published > 0) { - struct hash_iterator i; - hash_open(sDeviceFileSystem->vnode_hash, &i); - - while (true) { - devfs_vnode *vnode = (devfs_vnode *)hash_next( - sDeviceFileSystem->vnode_hash, &i); - if (vnode == NULL) - break; - - if (S_ISCHR(vnode->stream.type) - && vnode->stream.u.dev.driver == driver) { - void *dummy; - get_vnode(sDeviceFileSystem->volume, vnode->id, &dummy); - // We need to get/put the node, so that it is - // actually removed - - unpublish_node(sDeviceFileSystem, vnode, S_IFCHR); - put_vnode(sDeviceFileSystem->volume, vnode->id); - break; - } - } - - hash_close(sDeviceFileSystem->vnode_hash, &i, false); - } -} - - -static int32 -get_priority(const char* path) -{ - // TODO: would it be better to initialize a static structure here - // using find_directory()? - const directory_which whichPath[] = { - B_BEOS_DIRECTORY, - B_COMMON_DIRECTORY, - B_USER_DIRECTORY - }; - KPath pathBuffer; - - for (uint32 index = 0; index < sizeof(whichPath) / sizeof(whichPath[0]); - index++) { - if (find_directory(whichPath[index], gBootDevice, false, - pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { - pathBuffer.UnlockBuffer(); - if (!strncmp(pathBuffer.Path(), path, pathBuffer.BufferSize())) - return index; - } else - pathBuffer.UnlockBuffer(); - } - - return -1; -} - - -static const char * -get_leaf(const char *path) -{ - const char *name = strrchr(path, '/'); - if (name == NULL) - return path; - - return name + 1; -} - - -static driver_entry * -find_driver(dev_t device, ino_t node) -{ - hash_iterator iterator; - hash_open(sDeviceFileSystem->driver_hash, &iterator); - driver_entry *driver; - while (true) { - driver = (driver_entry *)hash_next(sDeviceFileSystem->driver_hash, - &iterator); - if (driver == NULL - || driver->device == device && driver->node == node) - break; - } - - hash_close(sDeviceFileSystem->driver_hash, &iterator, false); - return driver; -} - - -static status_t -add_driver(const char *path, image_id image) -{ - // see if we already know this driver - - struct stat stat; - if (image >= 0) { - // The image ID should be a small number and hopefully the boot FS - // doesn't use small negative values -- if it is inode based, we should - // be relatively safe. - stat.st_dev = -1; - stat.st_ino = -1; - } else { - if (::stat(path, &stat) != 0) - return errno; - } - - int32 priority = get_priority(path); - - RecursiveLocker locker(&sDeviceFileSystem->lock); - - driver_entry *driver = (driver_entry *)hash_lookup( - sDeviceFileSystem->driver_hash, get_leaf(path)); - if (driver != NULL) { - // we know this driver - // TODO: check if this driver is a different one and has precendence - // (ie. common supersedes system). - //dprintf("new driver has priority %ld, old %ld\n", priority, driver->priority); - if (priority >= driver->priority) { - driver->binary_updated = true; - return B_OK; - } - - // TODO: test for changes here and/or via node monitoring and reload - // the driver if necessary - if (driver->image < B_OK) - return driver->image; - - return B_OK; - } - - // we don't know this driver, create a new entry for it - - driver = (driver_entry *)malloc(sizeof(driver_entry)); - if (driver == NULL) - return B_NO_MEMORY; - - driver->path = strdup(path); - if (driver->path == NULL) { - free(driver); - return B_NO_MEMORY; - } - - driver->name = get_leaf(driver->path); - driver->device = stat.st_dev; - driver->node = stat.st_ino; - driver->image = image; - driver->last_modified = stat.st_mtime; - driver->devices_published = 0; - driver->devices_used = 0; - driver->binary_updated = false; - driver->priority = priority; - - driver->api_version = 1; - driver->find_device = NULL; - driver->publish_devices = NULL; - driver->uninit_driver = NULL; - driver->uninit_hardware = NULL; - - hash_insert(sDeviceFileSystem->driver_hash, driver); - if (stat.st_dev > 0) - add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_STAT, sDriverWatcher); - - // Even if loading the driver fails - its entry will stay with us - // so that we don't have to go through it again - return load_driver(driver); -} - - -/*! This is no longer part of the public kernel API, so we just export the - symbol -*/ -extern "C" status_t load_driver_symbols(const char *driverName); -status_t -load_driver_symbols(const char *driverName) -{ - // This is done globally for the whole kernel via the settings file. - // We don't have to do anything here. - - return B_OK; -} +// #pragma mark - devfs private static int32 @@ -652,7 +159,7 @@ scan_mode(void) static status_t -scan_for_drivers(devfs_vnode *dir) +scan_for_drivers(devfs_vnode* dir) { KPath path; if (path.InitCheck() != B_OK) @@ -664,116 +171,20 @@ scan_for_drivers(devfs_vnode *dir) TRACE(("scan_for_drivers: mode %ld: %s\n", scan_mode(), path.Path())); // scan for drivers at this path - probe_for_device_type(path.Path()); + static int32 updateCycle = 1; + device_manager_probe(path.Path(), updateCycle++); + legacy_driver_probe(path.Path()); dir->stream.u.dir.scanned = scan_mode(); return B_OK; } -static status_t -reload_driver(driver_entry *driver) -{ - dprintf("devfs: reload driver \"%s\"\n", driver->name); - - unload_driver(driver); - - status_t status = load_driver(driver); - if (status < B_OK) - unpublish_driver(driver); - - return status; -} - - -static void -handle_driver_events(void *_fs, int /*iteration*/) -{ - struct devfs *fs = (devfs *)_fs; - - if (atomic_and(&sDriverEvents, 0) == 0) - return; - - // something happened, let's see what it was - - RecursiveLocker locker(fs->lock); - - while (true) { - path_entry *path = sDriversToAdd.RemoveHead(); - if (path == NULL) - break; - - devfs_add_driver(path->path); - delete path; - } - - hash_iterator iterator; - hash_open(sDeviceFileSystem->driver_hash, &iterator); - driver_entry *driver; - while (true) { - driver = (driver_entry *)hash_next(sDeviceFileSystem->driver_hash, - &iterator); - if (driver == NULL) - break; - if (!driver->binary_updated || driver->devices_used != 0) - continue; - - // try to reload the driver - reload_driver(driver); - } - - hash_close(sDeviceFileSystem->driver_hash, &iterator, false); -} - - -// #pragma mark - DriverWatcher - - -DriverWatcher::DriverWatcher() -{ -} - - -DriverWatcher::~DriverWatcher() -{ -} - - -void -DriverWatcher::EventOccured(NotificationService& service, - const KMessage* event) -{ - if (event->GetInt32("opcode", -1) != B_STAT_CHANGED - || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) - return; - - RecursiveLocker locker(&sDeviceFileSystem->lock); - - driver_entry *driver = find_driver(event->GetInt32("device", -1), - event->GetInt64("node", 0)); - if (driver == NULL) - return; - - driver->binary_updated = true; -//dprintf("%s: devices published %ld, used %ld\n", driver->name, driver->devices_published, driver->devices_used); - if (driver->devices_used == 0) { - // trigger a reload of the driver - atomic_add(&sDriverEvents, 1); - } else { - // driver is in use right now - dprintf("devfs: changed driver \"%s\" is still in use\n", driver->name); - } -} - - -// #pragma mark - devfs private - - static uint32 -devfs_vnode_hash(void *_vnode, const void *_key, uint32 range) +devfs_vnode_hash(void* _vnode, const void* _key, uint32 range) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode; - const ino_t *key = (const ino_t *)_key; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode; + const ino_t* key = (const ino_t*)_key; if (vnode != NULL) return vnode->id % range; @@ -783,10 +194,10 @@ devfs_vnode_hash(void *_vnode, const void *_key, uint32 range) static int -devfs_vnode_compare(void *_vnode, const void *_key) +devfs_vnode_compare(void* _vnode, const void* _key) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode; - const ino_t *key = (const ino_t *)_key; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode; + const ino_t* key = (const ino_t*)_key; if (vnode->id == *key) return 0; @@ -795,12 +206,12 @@ devfs_vnode_compare(void *_vnode, const void *_key) } -static struct devfs_vnode * -devfs_create_vnode(struct devfs *fs, devfs_vnode *parent, const char *name) +static struct devfs_vnode* +devfs_create_vnode(struct devfs* fs, devfs_vnode* parent, const char* name) { - struct devfs_vnode *vnode; + struct devfs_vnode* vnode; - vnode = (struct devfs_vnode *)malloc(sizeof(struct devfs_vnode)); + vnode = (struct devfs_vnode*)malloc(sizeof(struct devfs_vnode)); if (vnode == NULL) return NULL; @@ -823,13 +234,13 @@ devfs_create_vnode(struct devfs *fs, devfs_vnode *parent, const char *name) static status_t -devfs_delete_vnode(struct devfs *fs, struct devfs_vnode *vnode, - bool force_delete) +devfs_delete_vnode(struct devfs* fs, struct devfs_vnode* vnode, + bool forceDelete) { // cant delete it if it's in a directory or is a directory // and has children - if (!force_delete - && ((S_ISDIR(vnode->stream.type) && vnode->stream.u.dir.dir_head != NULL) + if (!forceDelete && ((S_ISDIR(vnode->stream.type) + && vnode->stream.u.dir.dir_head != NULL) || vnode->dir_next != NULL)) return B_NOT_ALLOWED; @@ -845,10 +256,7 @@ devfs_delete_vnode(struct devfs *fs, struct devfs_vnode *vnode, vnode->stream.u.dev.partition->raw_device->id); } else { delete vnode->stream.u.dev.scheduler; - - // remove API conversion from old to new drivers - if (vnode->stream.u.dev.node == NULL) - free(vnode->stream.u.dev.info); + delete vnode->stream.u.dev.device; } } @@ -861,11 +269,11 @@ devfs_delete_vnode(struct devfs *fs, struct devfs_vnode *vnode, /*! Makes sure none of the dircookies point to the vnode passed in */ static void -update_dir_cookies(struct devfs_vnode *dir, struct devfs_vnode *vnode) +update_dir_cookies(struct devfs_vnode* dir, struct devfs_vnode* vnode) { - struct devfs_dir_cookie *cookie = NULL; + struct devfs_dir_cookie* cookie = NULL; - while ((cookie = (devfs_dir_cookie *)list_get_next_item( + while ((cookie = (devfs_dir_cookie*)list_get_next_item( &dir->stream.u.dir.cookies, cookie)) != NULL) { if (cookie->current == vnode) cookie->current = vnode->dir_next; @@ -873,10 +281,10 @@ update_dir_cookies(struct devfs_vnode *dir, struct devfs_vnode *vnode) } -static struct devfs_vnode * -devfs_find_in_dir(struct devfs_vnode *dir, const char *path) +static struct devfs_vnode* +devfs_find_in_dir(struct devfs_vnode* dir, const char* path) { - struct devfs_vnode *vnode; + struct devfs_vnode* vnode; if (!S_ISDIR(dir->stream.type)) return NULL; @@ -898,14 +306,15 @@ devfs_find_in_dir(struct devfs_vnode *dir, const char *path) static status_t -devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *vnode) +devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode) { if (!S_ISDIR(dir->stream.type)) return B_BAD_VALUE; // make sure the directory stays sorted alphabetically - devfs_vnode *node = dir->stream.u.dir.dir_head, *last = NULL; + devfs_vnode* node = dir->stream.u.dir.dir_head; + devfs_vnode* last = NULL; while (node && strcmp(node->name, vnode->name) < 0) { last = node; node = node->dir_next; @@ -933,7 +342,7 @@ devfs_insert_in_dir(struct devfs_vnode *dir, struct devfs_vnode *vnode) static status_t -devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *removeNode) +devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode) { struct devfs_vnode *vnode = dir->stream.u.dir.dir_head; struct devfs_vnode *lastNode = NULL; @@ -962,10 +371,10 @@ devfs_remove_from_dir(struct devfs_vnode *dir, struct devfs_vnode *removeNode) static status_t -add_partition(struct devfs *fs, struct devfs_vnode *device, - const char *name, const partition_info &info) +add_partition(struct devfs* fs, struct devfs_vnode* device, const char* name, + const partition_info& info) { - struct devfs_vnode *partitionNode; + struct devfs_vnode* partitionNode; status_t status; if (!S_ISCHR(device->stream.type)) @@ -980,14 +389,14 @@ add_partition(struct devfs *fs, struct devfs_vnode *device, return B_BAD_VALUE; // create partition - struct devfs_partition *partition = (struct devfs_partition *)malloc( + struct devfs_partition* partition = (struct devfs_partition*)malloc( sizeof(struct devfs_partition)); if (partition == NULL) return B_NO_MEMORY; memcpy(&partition->info, &info, sizeof(partition_info)); - RecursiveLocker locker(&fs->lock); + RecursiveLocker locker(fs->lock); // you cannot change a partition once set if (devfs_find_in_dir(device->parent, name)) { @@ -1009,9 +418,7 @@ add_partition(struct devfs *fs, struct devfs_vnode *device, } partitionNode->stream.type = device->stream.type; - partitionNode->stream.u.dev.node = device->stream.u.dev.node; - partitionNode->stream.u.dev.info = device->stream.u.dev.info; - partitionNode->stream.u.dev.ops = device->stream.u.dev.ops; + partitionNode->stream.u.dev.device = device->stream.u.dev.device; partitionNode->stream.u.dev.partition = partition; partitionNode->stream.u.dev.scheduler = device->stream.u.dev.scheduler; @@ -1031,8 +438,8 @@ err1: static inline void -translate_partition_access(devfs_partition *partition, off_t &offset, - size_t &size) +translate_partition_access(devfs_partition* partition, off_t& offset, + size_t& size) { ASSERT(offset >= 0); ASSERT(offset < partition->info.size); @@ -1105,10 +512,12 @@ unpublish_node(struct devfs *fs, devfs_vnode *node, mode_t type) status = remove_vnode(fs->volume, node->id); +#if 0 if (status == B_OK && S_ISCHR(node->stream.type) && node->stream.u.dev.driver != NULL) { node->stream.u.dev.driver->devices_published--; } +#endif out: recursive_lock_unlock(&fs->lock); @@ -1141,6 +550,7 @@ publish_directory(struct devfs *fs, const char *path) if (tempPath.InitCheck() != B_OK) return B_NO_MEMORY; + TRACE(("devfs: publish directory \"%s\"\n", path)); char *temp = tempPath.LockBuffer(); // create the path leading to the device @@ -1290,7 +700,7 @@ out: static void -publish_node(devfs *fs, devfs_vnode *dirNode, struct devfs_vnode *node) +publish_node(devfs* fs, devfs_vnode* dirNode, struct devfs_vnode* node) { hash_insert(fs->vnode_hash, node); devfs_insert_in_dir(dirNode, node); @@ -1298,36 +708,35 @@ publish_node(devfs *fs, devfs_vnode *dirNode, struct devfs_vnode *node) static status_t -publish_device(struct devfs *fs, const char *path, device_node_info *deviceNode, - pnp_devfs_driver_info *info, driver_entry *driver, device_hooks *ops, - int32 apiVersion) +publish_device(struct devfs* fs, const char* path, BaseDevice* device) { - TRACE(("publish_device(path = \"%s\", node = %p, info = %p, hooks = %p, apiVersion = %ld)\n", - path, deviceNode, info, ops, apiVersion)); + TRACE(("publish_device(path = \"%s\", device = %p)\n", path, device)); if (sDeviceFileSystem == NULL) { panic("publish_device() called before devfs mounted\n"); return B_ERROR; } - if ((ops == NULL && (deviceNode == NULL || info == NULL)) - || path == NULL || path[0] == '\0' || path[0] == '/') + if (device == NULL || path == NULL || path[0] == '\0' || path[0] == '/') return B_BAD_VALUE; +// TODO: this has to be done in the BaseDevice sub classes! +#if 0 // are the provided device hooks okay? - if ((ops != NULL && (ops->open == NULL || ops->close == NULL - || ops->read == NULL || ops->write == NULL)) - || info != NULL && (info->open == NULL || info->close == NULL - || info->read == NULL || info->write == NULL)) + if (info->device_open == NULL || info->device_close == NULL + || info->device_free == NULL + || ((info->device_read == NULL || info->device_write == NULL) + && info->device_io == NULL)) return B_BAD_VALUE; +#endif // mark disk devices - they might get an I/O scheduler bool isDisk = false; if (!strncmp(path, "disk/", 5)) isDisk = true; - struct devfs_vnode *node; - struct devfs_vnode *dirNode; + struct devfs_vnode* node; + struct devfs_vnode* dirNode; status_t status; RecursiveLocker locker(&fs->lock); @@ -1338,21 +747,9 @@ publish_device(struct devfs *fs, const char *path, device_node_info *deviceNode, // all went fine, let's initialize the node node->stream.type = S_IFCHR | 0644; + node->stream.u.dev.device = device; - if (deviceNode == NULL) { - info = create_new_driver_info(ops, apiVersion); - if (!info) - return B_NO_MEMORY; - } - - node->stream.u.dev.info = info; - node->stream.u.dev.node = deviceNode; - node->stream.u.dev.driver = driver; - node->stream.u.dev.ops = ops; - - if (driver != NULL) - driver->devices_published++; - +#if 0 // every raw disk gets an I/O scheduler object attached // ToDo: the driver should ask for a scheduler (ie. using its devfs node attributes) if (isDisk && !strcmp(node->name, "raw")) { @@ -1360,6 +757,7 @@ publish_device(struct devfs *fs, const char *path, device_node_info *deviceNode, if (!node->stream.u.dev.scheduler) return B_NO_MEMORY; } +#endif // the node is now fully valid and we may insert it into the dir publish_node(fs, dirNode, node); @@ -1372,7 +770,7 @@ publish_device(struct devfs *fs, const char *path, device_node_info *deviceNode, cannot be unpublished during the iteration). */ static void -get_device_name(struct devfs_vnode *vnode, char *buffer, size_t size) +get_device_name(struct devfs_vnode* vnode, char* buffer, size_t size) { struct devfs_vnode *leaf = vnode; size_t offset = 0; @@ -1434,76 +832,16 @@ dump_node(int argc, char **argv) } else if (S_ISLNK(vnode->stream.type)) { kprintf(" symlink to: %s\n", vnode->stream.u.symlink.path); } else { - kprintf(" device node: %p\n", vnode->stream.u.dev.node); - kprintf(" driver info: %p\n", vnode->stream.u.dev.info); - kprintf(" hooks: %p\n", vnode->stream.u.dev.ops); + kprintf(" device: %p\n", vnode->stream.u.dev.device); + kprintf(" node: %p\n", vnode->stream.u.dev.device->Node()); kprintf(" partition: %p\n", vnode->stream.u.dev.partition); kprintf(" scheduler: %p\n", vnode->stream.u.dev.scheduler); - kprintf(" driver: %p\n", vnode->stream.u.dev.driver); } return 0; } -static int -dump_driver(int argc, char **argv) -{ - if (argc < 2) { - // print list of all drivers - kprintf("address image used publ. pri name\n"); - hash_iterator iterator; - hash_open(sDeviceFileSystem->driver_hash, &iterator); - while (true) { - driver_entry *driver = (driver_entry *)hash_next( - sDeviceFileSystem->driver_hash, &iterator); - if (driver == NULL) - break; - - kprintf("%p %5ld %3ld %5ld %c %3ld %s\n", driver, - driver->image < 0 ? -1 : driver->image, - driver->devices_used, driver->devices_published, - driver->binary_updated ? 'U' : ' ', driver->priority, - driver->name); - } - - hash_close(sDeviceFileSystem->driver_hash, &iterator, false); - return 0; - } - - if (!strcmp(argv[1], "--help")) { - kprintf("usage: %s [name]\n", argv[0]); - return 0; - } - - driver_entry *driver = (driver_entry *)hash_lookup( - sDeviceFileSystem->driver_hash, argv[1]); - if (driver == NULL) { - kprintf("Driver named \"%s\" not found.\n", argv[1]); - return 0; - } - - kprintf("DEVFS DRIVER: %p\n", driver); - kprintf(" name: %s\n", driver->name); - kprintf(" path: %s\n", driver->path); - kprintf(" image: %ld\n", driver->image); - kprintf(" device: %ld\n", driver->device); - kprintf(" node: %Ld\n", driver->node); - kprintf(" last modified: %ld\n", driver->last_modified); - kprintf(" devs used: %ld\n", driver->devices_used); - kprintf(" devs published: %ld\n", driver->devices_published); - kprintf(" binary updated: %d\n", driver->binary_updated); - kprintf(" priority: %ld\n", driver->priority); - kprintf(" api version: %ld\n", driver->api_version); - kprintf(" hooks: find_device %p, publish_devices %p\n" - " uninit_driver %p, uninit_hardware %p\n", - driver->find_device, driver->publish_devices, driver->uninit_driver, - driver->uninit_hardware); - - return 0; -} - - // #pragma mark - file system interface @@ -1527,7 +865,7 @@ devfs_mount(fs_volume *volume, const char *devfs, uint32 flags, if (fs == NULL) { err = B_NO_MEMORY; goto err; - } + } volume->private_volume = fs; volume->ops = &kVolumeOps; @@ -1547,24 +885,11 @@ devfs_mount(fs_volume *volume, const char *devfs, uint32 flags, goto err2; } - fs->driver_hash = hash_init(DEVFS_HASH_SIZE, offsetof(driver_entry, next), - &driver_entry_compare, &driver_entry_hash); - if (fs->driver_hash == NULL) { - err = B_NO_MEMORY; - goto err3; - } - - new(&sDriverWatcher) DriverWatcher; - new(&sDriversToAdd) DoublyLinkedList; - - register_kernel_daemon(&handle_driver_events, fs, 10); - // once every second - // create a vnode vnode = devfs_create_vnode(fs, NULL, ""); if (vnode == NULL) { err = B_NO_MEMORY; - goto err4; + goto err3; } // set it up @@ -1583,8 +908,6 @@ devfs_mount(fs_volume *volume, const char *devfs, uint32 flags, sDeviceFileSystem = fs; return B_OK; -err4: - hash_uninit(fs->driver_hash); err3: hash_uninit(fs->vnode_hash); err2: @@ -1605,18 +928,8 @@ devfs_unmount(fs_volume *_volume) TRACE(("devfs_unmount: entry fs = %p\n", fs)); - unregister_kernel_daemon(&handle_driver_events, fs); - recursive_lock_lock(&fs->lock); - while (true) { - path_entry *entry = sDriversToAdd.RemoveHead(); - if (entry == NULL) - break; - - delete entry; - } - // release the reference to the root put_vnode(fs->volume, fs->root_vnode->id); @@ -1626,9 +939,7 @@ devfs_unmount(fs_volume *_volume) devfs_delete_vnode(fs, vnode, true); } hash_close(fs->vnode_hash, &i, false); - hash_uninit(fs->vnode_hash); - hash_uninit(fs->driver_hash); recursive_lock_destroy(&fs->lock); free(fs); @@ -1709,7 +1020,7 @@ devfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_vnode, int *_type, if (vnode == NULL) return B_ENTRY_NOT_FOUND; - TRACE(("devfs_get_vnode: looked it up at %p\n", *_vnode)); + TRACE(("devfs_get_vnode: looked it up at %p\n", vnode)); _vnode->private_node = vnode; _vnode->ops = &kVnodeOps; @@ -1720,10 +1031,10 @@ devfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_vnode, int *_type, static status_t -devfs_put_vnode(fs_volume *_volume, fs_vnode *_v, bool reenter) +devfs_put_vnode(fs_volume* _volume, fs_vnode* _vnode, bool reenter) { #ifdef TRACE_DEVFS - struct devfs_vnode *vnode = (struct devfs_vnode *)_v->private_node; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; TRACE(("devfs_put_vnode: entry on vnode %p, id = %Ld, reenter %d\n", vnode, vnode->id, reenter)); @@ -1755,119 +1066,109 @@ devfs_remove_vnode(fs_volume *_volume, fs_vnode *_v, bool reenter) static status_t -devfs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int openMode, - int perms, void **_cookie, ino_t *_newVnodeID) +devfs_create(fs_volume* _volume, fs_vnode* _dir, const char* name, int openMode, + int perms, void** _cookie, ino_t* _newVnodeID) { - struct devfs_vnode *dir = (struct devfs_vnode *)_dir->private_node; - struct devfs *fs = (struct devfs *)_volume->private_volume; - struct devfs_cookie *cookie; - struct devfs_vnode *vnode, *vdummy; + struct devfs_vnode* dir = (struct devfs_vnode*)_dir->private_node; + struct devfs* fs = (struct devfs*)_volume->private_volume; + struct devfs_cookie* cookie; + struct devfs_vnode* vnode; status_t status = B_OK; TRACE(("devfs_create: dir %p, name \"%s\", openMode 0x%x, fs_cookie %p \n", dir, name, openMode, _cookie)); - RecursiveLocker locker(&fs->lock); + RecursiveLocker locker(fs->lock); // look it up vnode = devfs_find_in_dir(dir, name); - if (!vnode) { - status = EROFS; - goto err1; - } + if (vnode == NULL) + return EROFS; if (openMode & O_EXCL) return B_FILE_EXISTS; - status = get_vnode(fs->volume, vnode->id, (void**)&vdummy); + status = get_vnode(fs->volume, vnode->id, NULL); if (status < B_OK) - goto err1; + return status; *_newVnodeID = vnode->id; - cookie = (struct devfs_cookie *)malloc(sizeof(struct devfs_cookie)); + cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie)); if (cookie == NULL) { status = B_NO_MEMORY; - goto err2; + goto err1; } if (S_ISCHR(vnode->stream.type)) { - if (vnode->stream.u.dev.node != NULL) { - status = vnode->stream.u.dev.info->open( - vnode->stream.u.dev.node->parent->cookie, openMode, - &cookie->device_cookie); - } else { - char buffer[B_FILE_NAME_LENGTH]; - get_device_name(vnode, buffer, sizeof(buffer)); + BaseDevice* device = vnode->stream.u.dev.device; + status = device->InitDevice(); + if (status < B_OK) + return status; - status = vnode->stream.u.dev.ops->open(buffer, openMode, - &cookie->device_cookie); - } + char path[B_FILE_NAME_LENGTH]; + get_device_name(vnode, path, sizeof(path)); + + locker.Unlock(); + + status = device->Open(path, openMode, &cookie->device_cookie); + + locker.Lock(); + + if (status != B_OK) + device->UninitDevice(); } if (status < B_OK) - goto err3; + goto err2; *_cookie = cookie; return B_OK; -err3: - free(cookie); err2: - put_vnode(fs->volume, vnode->id); + free(cookie); err1: + put_vnode(fs->volume, vnode->id); return status; } static status_t -devfs_open(fs_volume *_volume, fs_vnode *_vnode, int openMode, - void **_cookie) +devfs_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, + void** _cookie) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; - struct devfs *fs = (struct devfs *)_volume->private_volume; - struct devfs_cookie *cookie; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; + struct devfs* fs = (struct devfs*)_volume->private_volume; + struct devfs_cookie* cookie; status_t status = B_OK; TRACE(("devfs_open: vnode %p, openMode 0x%x, fs_cookie %p \n", vnode, openMode, _cookie)); - cookie = (struct devfs_cookie *)malloc(sizeof(struct devfs_cookie)); + cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie)); if (cookie == NULL) return B_NO_MEMORY; + cookie->device_cookie = NULL; + if (S_ISCHR(vnode->stream.type)) { RecursiveLocker locker(fs->lock); - driver_entry *driver = vnode->stream.u.dev.driver; - // TODO: we might want to check if the current node does still exist - // (it should fail in the driver's open(), though, if it doesn't) - if (driver != NULL - && driver->devices_used == 0 - && (driver->image < 0 || driver->binary_updated)) { - status = reload_driver(driver); - if (status < B_OK) { - free(cookie); - return status; - } - } + BaseDevice* device = vnode->stream.u.dev.device; + status = device->InitDevice(); + if (status < B_OK) + return status; + + char path[B_FILE_NAME_LENGTH]; + get_device_name(vnode, path, sizeof(path)); locker.Unlock(); - if (vnode->stream.u.dev.node != NULL) { - status = vnode->stream.u.dev.info->open( - vnode->stream.u.dev.node->parent->cookie, openMode, - &cookie->device_cookie); - } else { - char buffer[B_FILE_NAME_LENGTH]; - get_device_name(vnode, buffer, sizeof(buffer)); - - status = vnode->stream.u.dev.ops->open(buffer, openMode, - &cookie->device_cookie); - } + status = device->Open(path, openMode, &cookie->device_cookie); locker.Lock(); - if (status == B_OK && driver != NULL) - driver->devices_used++; + if (status != B_OK) + device->UninitDevice(); } + if (status < B_OK) free(cookie); else @@ -1887,7 +1188,7 @@ devfs_close(fs_volume *_volume, fs_vnode *_vnode, void *_cookie) if (S_ISCHR(vnode->stream.type)) { // pass the call through to the underlying device - return vnode->stream.u.dev.info->close(cookie->device_cookie); + return vnode->stream.u.dev.device->Close(cookie->device_cookie); } return B_OK; @@ -1905,12 +1206,15 @@ devfs_free_cookie(fs_volume *_volume, fs_vnode *_vnode, void *_cookie) if (S_ISCHR(vnode->stream.type)) { // pass the call through to the underlying device - vnode->stream.u.dev.info->free(cookie->device_cookie); + vnode->stream.u.dev.device->Free(cookie->device_cookie); RecursiveLocker _(fs->lock); + vnode->stream.u.dev.device->UninitDevice(); +#if 0 if (vnode->stream.u.dev.driver != NULL) vnode->stream.u.dev.driver->devices_used--; +#endif } free(cookie); @@ -1944,11 +1248,11 @@ devfs_read_link(fs_volume *_volume, fs_vnode *_link, char *buffer, static status_t -devfs_read(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, off_t pos, - void *buffer, size_t *_length) +devfs_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, + void* buffer, size_t* _length) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; - struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; + struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; //TRACE(("devfs_read: vnode %p, cookie %p, pos %Ld, len %p\n", // vnode, cookie, pos, _length)); @@ -1970,7 +1274,7 @@ devfs_read(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, off_t pos, return B_OK; // if this device has an I/O scheduler attached, the request must go through it - if (IOScheduler *scheduler = vnode->stream.u.dev.scheduler) { + if (IOScheduler* scheduler = vnode->stream.u.dev.scheduler) { IORequest request(cookie->device_cookie, pos, buffer, *_length); status_t status = scheduler->Process(request); @@ -1981,16 +1285,17 @@ devfs_read(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, off_t pos, } // pass the call through to the device - return vnode->stream.u.dev.info->read(cookie->device_cookie, pos, buffer, _length); + return vnode->stream.u.dev.device->Read(cookie->device_cookie, pos, buffer, + _length); } static status_t -devfs_write(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, off_t pos, - const void *buffer, size_t *_length) +devfs_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, + const void* buffer, size_t* _length) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; - struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; + struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; //TRACE(("devfs_write: vnode %p, cookie %p, pos %Ld, len %p\n", // vnode, cookie, pos, _length)); @@ -2011,7 +1316,7 @@ devfs_write(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, off_t pos, if (*_length == 0) return B_OK; - if (IOScheduler *scheduler = vnode->stream.u.dev.scheduler) { + if (IOScheduler* scheduler = vnode->stream.u.dev.scheduler) { IORequest request(cookie->device_cookie, pos, buffer, *_length); status_t status = scheduler->Process(request); @@ -2021,7 +1326,8 @@ devfs_write(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, off_t pos, return status; } - return vnode->stream.u.dev.info->write(cookie->device_cookie, pos, buffer, _length); + return vnode->stream.u.dev.device->Write(cookie->device_cookie, pos, buffer, + _length); } @@ -2218,7 +1524,7 @@ devfs_ioctl(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, ulong op, break; device_geometry geometry; - status_t status = vnode->stream.u.dev.info->control( + status_t status = vnode->stream.u.dev.device->Control( cookie->device_cookie, op, &geometry, length); if (status < B_OK) return status; @@ -2237,7 +1543,8 @@ devfs_ioctl(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, ulong op, case B_GET_DRIVER_FOR_DEVICE: { - const char *path; + const char* path; +#if 0 if (!vnode->stream.u.dev.driver) return B_ENTRY_NOT_FOUND; path = vnode->stream.u.dev.driver->path; @@ -2245,6 +1552,8 @@ devfs_ioctl(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, ulong op, return B_ENTRY_NOT_FOUND; return user_strlcpy((char *)buffer, path, B_FILE_NAME_LENGTH); +#endif + return B_ERROR; } case B_GET_PARTITION_INFO: @@ -2292,7 +1601,7 @@ devfs_ioctl(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, ulong op, } - return vnode->stream.u.dev.info->control(cookie->device_cookie, + return vnode->stream.u.dev.device->Control(cookie->device_cookie, op, buffer, length); } @@ -2301,56 +1610,56 @@ devfs_ioctl(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, ulong op, static status_t -devfs_set_flags(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, +devfs_set_flags(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, int flags) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; - struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; + struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; // we need to pass the O_NONBLOCK flag to the underlying device if (!S_ISCHR(vnode->stream.type)) return B_NOT_ALLOWED; - return vnode->stream.u.dev.info->control(cookie->device_cookie, + return vnode->stream.u.dev.device->Control(cookie->device_cookie, flags & O_NONBLOCK ? B_SET_NONBLOCKING_IO : B_SET_BLOCKING_IO, NULL, 0); } static status_t -devfs_select(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, - uint8 event, selectsync *sync) +devfs_select(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, + uint8 event, selectsync* sync) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; - struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; + struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; if (!S_ISCHR(vnode->stream.type)) return B_NOT_ALLOWED; // If the device has no select() hook, notify select() now. - if (!vnode->stream.u.dev.info->select) + if (!vnode->stream.u.dev.device->HasSelect()) return notify_select_event((selectsync*)sync, event); - return vnode->stream.u.dev.info->select(cookie->device_cookie, event, 0, + return vnode->stream.u.dev.device->Select(cookie->device_cookie, event, (selectsync*)sync); } static status_t -devfs_deselect(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, - uint8 event, selectsync *sync) +devfs_deselect(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, + uint8 event, selectsync* sync) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; - struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; + struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; if (!S_ISCHR(vnode->stream.type)) return B_NOT_ALLOWED; // If the device has no select() hook, notify select() now. - if (!vnode->stream.u.dev.info->deselect) + if (!vnode->stream.u.dev.device->HasDeselect()) return B_OK; - return vnode->stream.u.dev.info->deselect(cookie->device_cookie, event, + return vnode->stream.u.dev.device->Deselect(cookie->device_cookie, event, (selectsync*)sync); } @@ -2363,12 +1672,12 @@ devfs_can_page(fs_volume *_volume, fs_vnode *_vnode, void *cookie) //TRACE(("devfs_canpage: vnode %p\n", vnode)); if (!S_ISCHR(vnode->stream.type) - || vnode->stream.u.dev.node == NULL + || vnode->stream.u.dev.device->Node() == NULL || cookie == NULL) return false; - return vnode->stream.u.dev.info->read_pages != NULL - || vnode->stream.u.dev.info->read != NULL; + return vnode->stream.u.dev.device->HasRead() + || vnode->stream.u.dev.device->HasIO(); } @@ -2382,8 +1691,8 @@ devfs_read_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, //TRACE(("devfs_read_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes)); if (!S_ISCHR(vnode->stream.type) - || (vnode->stream.u.dev.info->read_pages == NULL - && vnode->stream.u.dev.info->read == NULL) + || (!vnode->stream.u.dev.device->HasRead() + && !vnode->stream.u.dev.device->HasIO()) || cookie == NULL) return B_NOT_ALLOWED; @@ -2397,9 +1706,8 @@ devfs_read_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, *_numBytes); } - if (vnode->stream.u.dev.info->read_pages) { - return vnode->stream.u.dev.info->read_pages(cookie->device_cookie, pos, - vecs, count, _numBytes); + if (vnode->stream.u.dev.device->HasIO()) { + // TODO: use io_requests for this! } // emulate read_pages() using read() @@ -2412,7 +1720,7 @@ devfs_read_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, size_t toRead = min_c(vecs[i].iov_len, remainingBytes); size_t length = toRead; - error = vnode->stream.u.dev.info->read(cookie->device_cookie, pos, + error = vnode->stream.u.dev.device->Read(cookie->device_cookie, pos, vecs[i].iov_base, &length); if (error != B_OK) break; @@ -2427,13 +1735,13 @@ devfs_read_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, *_numBytes = bytesTransferred; - return (bytesTransferred > 0 ? B_OK : error); + return bytesTransferred > 0 ? B_OK : error; } static status_t -devfs_write_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, - off_t pos, const iovec *vecs, size_t count, size_t *_numBytes, bool reenter) +devfs_write_pages(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, + off_t pos, const iovec* vecs, size_t count, size_t* _numBytes, bool reenter) { struct devfs_vnode *vnode = (devfs_vnode *)_vnode->private_node; struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; @@ -2441,8 +1749,8 @@ devfs_write_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, //TRACE(("devfs_write_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes)); if (!S_ISCHR(vnode->stream.type) - || (vnode->stream.u.dev.info->write_pages == NULL - && vnode->stream.u.dev.info->write == NULL) + || (!vnode->stream.u.dev.device->HasWrite() + && !vnode->stream.u.dev.device->HasIO()) || cookie == NULL) return B_NOT_ALLOWED; @@ -2456,9 +1764,8 @@ devfs_write_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, *_numBytes); } - if (vnode->stream.u.dev.info->write_pages) { - return vnode->stream.u.dev.info->write_pages(cookie->device_cookie, pos, - vecs, count, _numBytes); + if (vnode->stream.u.dev.device->HasIO()) { + // TODO: use io_requests for this! } // emulate write_pages() using write() @@ -2471,7 +1778,7 @@ devfs_write_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, size_t toWrite = min_c(vecs[i].iov_len, remainingBytes); size_t length = toWrite; - error = vnode->stream.u.dev.info->write(cookie->device_cookie, pos, + error = vnode->stream.u.dev.device->Write(cookie->device_cookie, pos, vecs[i].iov_base, &length); if (error != B_OK) break; @@ -2486,14 +1793,14 @@ devfs_write_pages(fs_volume *_volume, fs_vnode *_vnode, void *_cookie, *_numBytes = bytesTransferred; - return (bytesTransferred > 0 ? B_OK : error); + return bytesTransferred > 0 ? B_OK : error; } static status_t -devfs_read_stat(fs_volume *_volume, fs_vnode *_vnode, struct stat *stat) +devfs_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* stat) { - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; TRACE(("devfs_read_stat: vnode %p (%Ld), stat %p\n", vnode, vnode->id, stat)); @@ -2540,11 +1847,11 @@ devfs_read_stat(fs_volume *_volume, fs_vnode *_vnode, struct stat *stat) static status_t -devfs_write_stat(fs_volume *_volume, fs_vnode *_vnode, const struct stat *stat, +devfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const struct stat* stat, uint32 statMask) { - struct devfs *fs = (struct devfs *)_volume->private_volume; - struct devfs_vnode *vnode = (struct devfs_vnode *)_vnode->private_node; + struct devfs* fs = (struct devfs*)_volume->private_volume; + struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; TRACE(("devfs_write_stat: vnode %p (0x%Lx), stat %p\n", vnode, vnode->id, stat)); @@ -2582,13 +1889,12 @@ devfs_std_ops(int32 op, ...) case B_MODULE_INIT: add_debugger_command("devfs_node", &dump_node, "info about a private devfs node"); - add_debugger_command("devfs_driver", &dump_driver, - "info about a devfs driver entry"); + + legacy_driver_init(); return B_OK; case B_MODULE_UNINIT: remove_debugger_command("devfs_node", &dump_node); - remove_debugger_command("devfs_driver", &dump_driver); return B_OK; default: @@ -2683,269 +1989,9 @@ file_system_module_info gDeviceFileSystem = { }; -// #pragma mark - device node -// temporary hack to get it to work with the current device manager - - -static device_manager_info *sDeviceManager; - - -static const device_attr pnp_devfs_attrs[] = { - { B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }}, - { NULL } -}; - - -/*! Someone registered a device */ -static status_t -pnp_devfs_register_device(device_node_handle parent) -{ - char *filename = NULL; - device_node_handle node; - status_t status; - - TRACE(("pnp_devfs_probe()\n")); - - if (sDeviceManager->get_attr_string(parent, PNP_DEVFS_FILENAME, - &filename, true) != B_OK) { - dprintf("devfs: Item containing file name is missing\n"); - status = B_ERROR; - goto err1; - } - - TRACE(("Adding %s\n", filename)); - - status = sDeviceManager->register_device(parent, pnp_devfs_attrs, NULL, - &node); - if (status != B_OK || node == NULL) - goto err1; - - // ToDo: this is a hack to get things working (init_driver() only - // works for registered nodes) - parent->registered = true; - - pnp_devfs_driver_info *info; - status = sDeviceManager->init_driver(parent, NULL, - (driver_module_info **)&info, NULL); - if (status != B_OK) - goto err2; - - //add_device(device); - status = publish_device(sDeviceFileSystem, filename, node, info, NULL, - NULL, 0); - if (status != B_OK) - goto err3; - //nudge(); - - return B_OK; - -err3: - sDeviceManager->uninit_driver(parent); -err2: - sDeviceManager->unregister_device(node); -err1: - free(filename); - - return status; -} - - -#if 0 -// remove device from public list and add it to unpublish list -// (devices_lock must be hold) -static void -pnp_devfs_remove_device(device_info *device) -{ - TRACE(("removing device %s from public list\n", device->name)); - - --num_devices; - REMOVE_DL_LIST( device, devices, ); - - ++num_unpublished_devices; - ADD_DL_LIST_HEAD( device, devices_to_unpublish, ); - - // (don't free it even if no handle is open - the device - // info block contains the hook list which may just got passed - // to the devfs layer; we better wait until next - // publish_devices, so we are sure that devfs won't access - // the hook list anymore) -} -#endif - - -// device got removed -static void -pnp_devfs_device_removed(device_node_handle node, void *cookie) -{ -#if 0 - device_info *device; - device_node_handle parent; - status_t res = B_OK; -#endif - TRACE(("pnp_devfs_device_removed()\n")); -#if 0 - parent = sDeviceManager->get_parent(node); - - // don't use cookie - we don't use sDeviceManager loading scheme but - // global data and keep care of everything ourself! - ACQUIRE_BEN( &device_list_lock ); - - for( device = devices; device; device = device->next ) { - if( device->parent == parent ) - break; - } - - if( device != NULL ) { - pnp_devfs_remove_device(device); - } else { - SHOW_ERROR( 0, "bug: node %p couldn't been found", node ); - res = B_NAME_NOT_FOUND; - } - - RELEASE_BEN( &device_list_lock ); - - //nudge(); -#endif -} - - -static status_t -pnp_devfs_std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - return get_module(B_DEVICE_MANAGER_MODULE_NAME, - (module_info **)&sDeviceManager); - - case B_MODULE_UNINIT: - put_module(B_DEVICE_MANAGER_MODULE_NAME); - return B_OK; - - default: - return B_ERROR; - } -} - - -driver_module_info gDeviceForDriversModule = { - { - PNP_DEVFS_MODULE_NAME, - 0 /*B_KEEP_LOADED*/, - pnp_devfs_std_ops - }, - - NULL, // supports device - pnp_devfs_register_device, - NULL, // init driver - NULL, // uninit driver - pnp_devfs_device_removed, - NULL, // cleanup - NULL, // get paths -}; - - // #pragma mark - kernel private API -extern "C" void -devfs_add_preloaded_drivers(kernel_args* args) -{ - // NOTE: This function does not exit in case of error, since it - // needs to unload the images then. Also the return code of - // the path operations is kept separate from the add_driver() - // success, so that even if add_driver() fails for one driver, it - // is still tried for the other drivers. - // NOTE: The initialization success of the path objects is implicitely - // checked by the immediately following functions. - KPath basePath; - status_t pathStatus = find_directory(B_BEOS_ADDONS_DIRECTORY, - gBootDevice, false, basePath.LockBuffer(), basePath.BufferSize()); - if (pathStatus != B_OK) { - dprintf("devfs_add_preloaded_drivers: find_directory() failed: " - "%s\n", strerror(pathStatus)); - } - basePath.UnlockBuffer(); - if (pathStatus == B_OK) - pathStatus = basePath.Append("kernel"); - if (pathStatus != B_OK) { - dprintf("devfs_add_preloaded_drivers: constructing base driver " - "path failed: %s\n", strerror(pathStatus)); - } - - struct preloaded_image* image; - for (image = args->preloaded_images; image != NULL; image = image->next) { - if (image->is_module || image->id < 0) - continue; - - KPath imagePath(basePath); - if (pathStatus == B_OK) - pathStatus = imagePath.Append(image->name); - - // try to add the driver - status_t addStatus = pathStatus; - if (pathStatus == B_OK) - addStatus = add_driver(imagePath.Path(), image->id); - if (addStatus != B_OK) { - dprintf("devfs_add_preloaded_drivers: Failed to add \"%s\"\n", - image->name); - unload_kernel_add_on(image->id); - } - } -} - - -extern "C" status_t -devfs_add_driver(const char *path) -{ - return add_driver(path, -1); -} - - -extern "C" void -devfs_driver_added(const char *path) -{ - int32 priority = get_priority(path); - RecursiveLocker locker(&sDeviceFileSystem->lock); - - driver_entry *driver = (driver_entry *)hash_lookup( - sDeviceFileSystem->driver_hash, get_leaf(path)); - - if (driver == NULL) { - // Add the driver to our list - path_entry *entry = new(std::nothrow) path_entry; - if (entry == NULL) - return; - - strlcpy(entry->path, path, sizeof(entry->path)); - sDriversToAdd.Add(entry); - } else { - // Update the driver if it is affected by the new entry - if (priority < driver->priority) - return; - - driver->binary_updated = true; - } - - atomic_add(&sDriverEvents, 1); -} - - -extern "C" void -devfs_driver_removed(const char *path) -{ - int32 priority = get_priority(path); - RecursiveLocker locker(&sDeviceFileSystem->lock); - - driver_entry *driver = (driver_entry *)hash_lookup( - sDeviceFileSystem->driver_hash, get_leaf(path)); - if (driver == NULL || priority < driver->priority) - return; - - driver->binary_updated = true; - atomic_add(&sDriverEvents, 1); -} - - extern "C" status_t devfs_unpublish_file_device(const char *path) { @@ -2991,7 +2037,7 @@ devfs_unpublish_partition(const char *path) extern "C" status_t -devfs_publish_partition(const char *path, const partition_info *info) +devfs_publish_partition(const char* path, const partition_info* info) { if (path == NULL || info == NULL) return B_BAD_VALUE; @@ -3000,8 +2046,8 @@ devfs_publish_partition(const char *path, const partition_info *info) path, info->device, info->offset, info->size)); // the partition and device paths must be the same until the leaves - const char *lastPath = strrchr(path, '/'); - const char *lastDevice = strrchr(info->device, '/'); + const char* lastPath = strrchr(path, '/'); + const char* lastDevice = strrchr(info->device, '/'); if (lastPath == NULL || lastDevice == NULL) return B_BAD_VALUE; @@ -3009,7 +2055,7 @@ devfs_publish_partition(const char *path, const partition_info *info) if (strncmp(path, info->device + length, lastPath - path)) return B_BAD_VALUE; - devfs_vnode *device; + devfs_vnode* device; status_t status = get_node_for_path(sDeviceFileSystem, info->device, &device); if (status != B_OK) @@ -3023,9 +2069,18 @@ devfs_publish_partition(const char *path, const partition_info *info) extern "C" status_t -devfs_unpublish_device(const char *path, bool disconnect) +devfs_publish_directory(const char* path) { - devfs_vnode *node; + RecursiveLocker locker(&sDeviceFileSystem->lock); + + return publish_directory(sDeviceFileSystem, path); +} + + +extern "C" status_t +devfs_unpublish_device(const char* path, bool disconnect) +{ + devfs_vnode* node; status_t status = get_node_for_path(sDeviceFileSystem, path, &node); if (status != B_OK) return status; @@ -3040,35 +2095,29 @@ devfs_unpublish_device(const char *path, bool disconnect) } -extern "C" status_t -devfs_publish_device(const char *path, device_hooks *ops) +status_t +devfs_publish_device(const char* path, BaseDevice* device) { - // post R5: assume version 2 - return publish_device(sDeviceFileSystem, path, NULL, NULL, NULL, ops, 2); + return publish_device(sDeviceFileSystem, path, device); } -extern "C" status_t -devfs_publish_directory(const char *path) -{ - RecursiveLocker locker(&sDeviceFileSystem->lock); - - return publish_directory(sDeviceFileSystem, path); -} +// #pragma mark - support API for legacy drivers extern "C" status_t -devfs_rescan_driver(const char *driverName) +devfs_rescan_driver(const char* driverName) { TRACE(("devfs_rescan_driver: %s\n", driverName)); - RecursiveLocker locker(&sDeviceFileSystem->lock); - - driver_entry *driver = (driver_entry *)hash_lookup( - sDeviceFileSystem->driver_hash, driverName); - if (driver == NULL) - return B_ENTRY_NOT_FOUND; - - // Republish the driver's entries - return republish_driver(driver); + return legacy_driver_rescan(driverName); } + + +extern "C" status_t +devfs_publish_device(const char* path, device_hooks* hooks) +{ + return legacy_driver_publish(path, hooks); +} + + diff --git a/src/system/kernel/device_manager/devfs_private.h b/src/system/kernel/device_manager/devfs_private.h new file mode 100644 index 0000000000..120c5c57ea --- /dev/null +++ b/src/system/kernel/device_manager/devfs_private.h @@ -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 + + +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 */ diff --git a/src/system/kernel/device_manager/device_manager.cpp b/src/system/kernel/device_manager/device_manager.cpp new file mode 100644 index 0000000000..90de58c17f --- /dev/null +++ b/src/system/kernel/device_manager/device_manager.cpp @@ -0,0 +1,2060 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BaseDevice.h" +#include "devfs_private.h" +#include "id_generator.h" +#include "io_resources.h" + + +#define TRACE_DEVICE_MANAGER +#ifdef TRACE_DEVICE_MANAGER +# define TRACE(a) dprintf a +#else +# define TRACE(a) ; +#endif + + +#define DEVICE_MANAGER_ROOT_NAME "system/devices_root/driver_v1" + + +struct device_attr_private : device_attr, + DoublyLinkedListLinkImpl { + device_attr_private(); + device_attr_private(const device_attr& attr); + ~device_attr_private(); + + status_t InitCheck(); + status_t CopyFrom(const device_attr& attr); + + static int Compare(const device_attr* attrA, + const device_attr *attrB); + +private: + void _Unset(); +}; + +typedef DoublyLinkedList AttributeList; + +// I/O resource +typedef struct io_resource_info { + struct io_resource_info *prev, *next; + device_node* owner; // associated node; NULL for temporary allocation + io_resource resource; // info about actual resource +} io_resource_info; + +class Device : public BaseDevice, public DoublyLinkedListLinkImpl { +public: + Device(device_node* node, const char* moduleName); + virtual ~Device(); + + status_t InitCheck() const; + + const char* ModuleName() const { return fModuleName; } + + virtual status_t InitDevice(); + virtual void UninitDevice(); + +private: + const char* fModuleName; +}; + +typedef DoublyLinkedList DeviceList; +typedef DoublyLinkedList NodeList; + +struct device_node : DoublyLinkedListLinkImpl { + device_node(const char* moduleName, + const device_attr* attrs); + ~device_node(); + + status_t InitCheck() const; + + status_t AcquireResources(const io_resource* resources); + + const char* ModuleName() const { return fModuleName; } + device_node* Parent() const { return fParent; } + AttributeList& Attributes() { return fAttributes; } + const AttributeList& Attributes() const { return fAttributes; } + + status_t InitDriver(); + bool UninitDriver(); + void UninitUnusedDriver(); + + // The following two are only valid, if the node's driver is + // initialized + driver_module_info* DriverModule() const { return fDriver; } + void* DriverData() const { return fDriverData; } + + void AddChild(device_node *node); + void RemoveChild(device_node *node); + const NodeList& Children() const { return fChildren; } + void DeviceRemoved(); + + status_t Register(device_node* parent); + status_t Probe(const char* devicePath, uint32 updateCycle); + status_t Rescan(); + + bool IsRegistered() const { return fRegistered; } + bool IsInitialized() const { return fInitialized > 0; } + bool IsProbed() const { return fLastUpdateCycle != 0; } + uint32 Flags() const { return fFlags; } + + void Acquire(); + bool Release(); + + const DeviceList& Devices() const { return fDevices; } + void AddDevice(Device* device); + void RemoveDevice(Device* device); + + int CompareTo(const device_attr* attributes) const; + device_node* FindChild(const device_attr* attributes) const; + device_node* FindChild(const char* moduleName) const; + + void Dump(int32 level = 0); + +private: + status_t _RegisterFixed(uint32& registered); + bool _AlwaysRegisterDynamic(); + status_t _AddPath(Stack& stack, const char* path, + const char* subPath = NULL); + status_t _GetNextDriverPath(void*& cookie, KPath& _path); + status_t _GetNextDriver(void* list, + driver_module_info*& driver); + status_t _FindBestDriver(const char* path, + driver_module_info*& bestDriver, + float& bestSupport, + device_node* previous = NULL); + status_t _RegisterPath(const char* path); + status_t _RegisterDynamic(device_node* previous = NULL); + status_t _RemoveChildren(); + device_node* _FindCurrentChild(); + status_t _Rescan(); + void _ReleaseWaiting(); + + device_node* fParent; + NodeList fChildren; + int32 fRefCount; + int32 fInitialized; + bool fRegistered; + uint32 fFlags; + float fSupportsParent; + uint32 fLastUpdateCycle; + + const char* fModuleName; + + driver_module_info* fDriver; + void* fDriverData; + + DeviceList fDevices; + AttributeList fAttributes; + ResourceList fResources; +}; + +// flags in addition to those specified by B_DEVICE_FLAGS +enum node_flags { + NODE_FLAG_REGISTER_INITIALIZED = 0x00010000, + NODE_FLAG_DEVICE_REMOVED = 0x00020000, + NODE_FLAG_OBSOLETE_DRIVER = 0x00040000, + NODE_FLAG_WAITING_FOR_DRIVER = 0x00080000, + + NODE_FLAG_PUBLIC_MASK = 0x0000ffff +}; + + +static device_node *sRootNode; +static recursive_lock sLock; + +static uint32 sDriverUpdateCycle = 1; + + +// #pragma mark - + + +static device_attr_private* +find_attr(const device_node* node, const char* name, bool recursive, + type_code type) +{ + do { + AttributeList::ConstIterator iterator + = node->Attributes().GetIterator(); + + while (iterator.HasNext()) { + device_attr_private* attr = iterator.Next(); + + if (type != B_ANY_TYPE && attr->type != type) + continue; + + if (!strcmp(attr->name, name)) + return attr; + } + + node = node->Parent(); + } while (node != NULL && recursive); + + return NULL; +} + + +static void +put_level(int32 level) +{ + while (level-- > 0) + dprintf(" "); +} + + +static void +dump_attribute(device_attr* attr, int32 level) +{ + if (attr == NULL) + return; + + put_level(level + 2); + dprintf("\"%s\" : ", attr->name); + switch (attr->type) { + case B_STRING_TYPE: + dprintf("string : \"%s\"", attr->value.string); + break; + case B_INT8_TYPE: + case B_UINT8_TYPE: + dprintf("uint8 : %u (%#x)", attr->value.ui8, attr->value.ui8); + break; + case B_INT16_TYPE: + case B_UINT16_TYPE: + dprintf("uint16 : %u (%#x)", attr->value.ui16, attr->value.ui16); + break; + case B_INT32_TYPE: + case B_UINT32_TYPE: + dprintf("uint32 : %lu (%#lx)", attr->value.ui32, attr->value.ui32); + break; + case B_INT64_TYPE: + case B_UINT64_TYPE: + dprintf("uint64 : %Lu (%#Lx)", attr->value.ui64, attr->value.ui64); + break; + default: + dprintf("raw data"); + } + dprintf("\n"); +} + + +static int +dump_device_nodes(int argc, char **argv) +{ + sRootNode->Dump(); + return 0; +} + + +static void +publish_directories(const char* subPath) +{ + if (gBootDevice < 0) { + if (subPath[0]) { + // we only support the top-level directory for modules + return; + } + + // we can only iterate over the known modules to find all directories + KPath path("drivers"); + if (path.Append(subPath) != B_OK) + return; + + size_t length = strlen(path.Path()) + 1; + // account for the separating '/' + + void* list = open_module_list_etc(path.Path(), "driver_v1"); + char name[B_FILE_NAME_LENGTH]; + size_t nameLength = sizeof(name); + while (read_next_module_name(list, name, &nameLength) == B_OK) { + if (nameLength == length) + continue; + + char* leaf = name + length; + char* end = strchr(leaf, '/'); + if (end != NULL) + end[0] = '\0'; + + path.SetTo(subPath); + path.Append(leaf); + + devfs_publish_directory(path.Path()); + } + } else { + // TODO: implement module directory traversal! + } +} + + +static status_t +control_device_manager(const char* subsystem, uint32 function, void* buffer, + size_t bufferSize) +{ + switch (function) { + case DM_GET_ROOT: + { + return B_ERROR; +#if 0 + uint32 cookie; + if (!IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; + if (bufferSize < sizeof(uint32)) + return B_BAD_VALUE; + cookie = sRootNode->ID(); + + // copy back to user space + return user_memcpy(buffer, &cookie, sizeof(uint32)); +#endif + } + + case DM_GET_CHILD: + { + return B_ERROR; +#if 0 + device_node_info* node; + device_node_info* child; + + if (!IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; + if (bufferSize < sizeof(uint32)) + return B_BAD_VALUE; + + uint32 cookie; + if (user_memcpy(&cookie, buffer, sizeof(uint32)) < B_OK) + return B_BAD_ADDRESS; + + benaphore_lock(&gNodeLock); + node = device_manager_find_device(gRootNode, cookie); + if (!node) { + benaphore_unlock(&gNodeLock); + return B_BAD_VALUE; + } + + child = (device_node_info *)list_get_next_item(&node->children, NULL); + if (child) + cookie = child->internal_id; + benaphore_unlock(&gNodeLock); + + if (!child) + return B_ENTRY_NOT_FOUND; + // copy back to user space + return user_memcpy(buffer, &cookie, sizeof(uint32)); +#endif + } + + case DM_GET_NEXT_CHILD: + { + return B_ERROR; +#if 0 + device_node_info* node; + device_node_info* child; + + if (!IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; + if (bufferSize < sizeof(uint32)) + return B_BAD_VALUE; + + uint32 cookie; + if (user_memcpy(&cookie, buffer, sizeof(uint32)) < B_OK) + return B_BAD_ADDRESS; + + benaphore_lock(&gNodeLock); + node = device_manager_find_device(gRootNode, cookie); + if (!node) { + benaphore_unlock(&gNodeLock); + return B_BAD_VALUE; + } + child = (device_node_info *)list_get_next_item(&node->parent->children, node); + if (child) + cookie = child->internal_id; + benaphore_unlock(&gNodeLock); + + if (!child) + return B_ENTRY_NOT_FOUND; + // copy back to user space + return user_memcpy(buffer, &cookie, sizeof(uint32)); +#endif + } + + case DM_GET_NEXT_ATTRIBUTE: + { + return B_ERROR; +#if 0 + struct dev_attr attr; + device_node_info* node; + uint32 i = 0; + device_attr_info *attr_info; + if (!IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; + if (bufferSize < sizeof(struct dev_attr)) + return B_BAD_VALUE; + if (user_memcpy(&attr, buffer, sizeof(struct dev_attr)) < B_OK) + return B_BAD_ADDRESS; + + benaphore_lock(&gNodeLock); + node = device_manager_find_device(gRootNode, attr.node_cookie); + if (!node) { + benaphore_unlock(&gNodeLock); + return B_BAD_VALUE; + } + for (attr_info = node->attributes; attr.cookie > i && attr_info != NULL; attr_info = attr_info->next) { + i++; + } + + if (!attr_info) { + benaphore_unlock(&gNodeLock); + return B_ENTRY_NOT_FOUND; + } + + attr.cookie++; + + strlcpy(attr.name, attr_info->attr.name, 254); + attr.type = attr_info->attr.type; + switch (attr_info->attr.type) { + case B_UINT8_TYPE: + attr.value.ui8 = attr_info->attr.value.ui8; break; + case B_UINT16_TYPE: + attr.value.ui16 = attr_info->attr.value.ui16; break; + case B_UINT32_TYPE: + attr.value.ui32 = attr_info->attr.value.ui32; break; + case B_UINT64_TYPE: + attr.value.ui64 = attr_info->attr.value.ui64; break; + case B_STRING_TYPE: + strlcpy(attr.value.string, attr_info->attr.value.string, 254); break; + /*case B_RAW_TYPE: + if (attr.value.raw.length > attr_info->attr.value.raw.length) + attr.value.raw.length = attr_info->attr.value.raw.length; + user_memcpy(attr.value.raw.data, attr_info->attr.value.raw.data, + attr.value.raw.length); + break;*/ + } + + benaphore_unlock(&gNodeLock); + + // copy back to user space + return user_memcpy(buffer, &attr, sizeof(struct dev_attr)); +#endif + } + } + + return B_BAD_HANDLER; +} + + +// #pragma mark - Device Manager module API + + +static status_t +rescan_node(device_node* node) +{ + RecursiveLocker _(sLock); + return node->Rescan(); +} + + +static status_t +register_node(device_node* parent, const char* moduleName, + const device_attr* attrs, const io_resource* ioResources, + device_node** _node) +{ + if ((parent == NULL && sRootNode != NULL) || moduleName == NULL) + return B_BAD_VALUE; + + if (parent != NULL && parent->FindChild(attrs) != NULL) { + // A node like this one already exists for this parent + return B_NAME_IN_USE; + } + + RecursiveLocker _(sLock); + + device_node* newNode = new(std::nothrow) device_node(moduleName, attrs); + if (newNode == NULL) + return B_NO_MEMORY; + + TRACE(("%p: register node \"%s\", parent %p\n", newNode, moduleName, + parent)); + + status_t status = newNode->InitCheck(); + if (status == B_OK) + status = newNode->AcquireResources(ioResources); + if (status == B_OK) + status = newNode->Register(parent); + + if (status != B_OK) { + newNode->Release(); + return status; + } + + if (_node) + *_node = newNode; + + return B_OK; +} + + +/*! Unregisters the device \a node. + + If the node is currently in use, this function will return B_BUSY to + indicate that the node hasn't been removed yet - it will still remove + the node as soon as possible. +*/ +static status_t +unregister_node(device_node* node) +{ + TRACE(("unregister_node(node %p)\n", node)); + RecursiveLocker _(sLock); + + bool initialized = node->IsInitialized(); + + node->DeviceRemoved(); + + return initialized ? B_BUSY : B_OK; +} + + +static status_t +get_driver(device_node* node, driver_module_info** _module, void** _data) +{ + if (node->DriverModule() == NULL) + return B_NO_INIT; + + if (_module != NULL) + *_module = node->DriverModule(); + if (_data != NULL) + *_data = node->DriverData(); + + return B_OK; +} + + +static device_node* +get_root_node(void) +{ + if (sRootNode != NULL) + sRootNode->Acquire(); + + return sRootNode; +} + + +static status_t +get_next_child_node(device_node* parent, const device_attr* attributes, + device_node** _node) +{ + RecursiveLocker _(sLock); + + NodeList::ConstIterator iterator = parent->Children().GetIterator(); + device_node* last = *_node; + + // skip those we already traversed + while (iterator.HasNext() && last != NULL) { + device_node* node = iterator.Next(); + + if (node != last) + continue; + } + + // find the next one that fits + while (iterator.HasNext()) { + device_node* node = iterator.Next(); + + if (!node->IsRegistered()) + continue; + + if (!node->CompareTo(attributes)) { + if (last != NULL) + last->Release(); + + node->Acquire(); + *_node = node; + return B_OK; + } + } + + if (last != NULL) + last->Release(); + + return B_ENTRY_NOT_FOUND; +} + + +static device_node* +get_parent_node(device_node* node) +{ + if (node == NULL) + return NULL; + + RecursiveLocker _(sLock); + + device_node* parent = node->Parent(); + parent->Acquire(); + + return parent; +} + + +static void +put_node(device_node* node) +{ + RecursiveLocker _(sLock); + node->Release(); +} + + +static status_t +publish_device(device_node *node, const char *path, const char *moduleName) +{ + if (path == NULL || !path[0] || moduleName == NULL || !moduleName[0]) + return B_BAD_VALUE; + + RecursiveLocker _(sLock); + dprintf("publish device: node %p, path %s, module %s\n", node, path, + moduleName); + + Device* device = new(std::nothrow) Device(node, moduleName); + if (device == NULL) + return B_NO_MEMORY; + + status_t status = device->InitCheck(); + if (status == B_OK) + status = devfs_publish_device(path, device); + if (status != B_OK) { + delete device; + return status; + } + + node->AddDevice(device); + return B_OK; +} + + +static status_t +unpublish_device(device_node *node, const char *path) +{ + if (path == NULL) + return B_BAD_VALUE; + + RecursiveLocker _(sLock); + +#if 0 + DeviceList::ConstIterator iterator = node->Devices().GetIterator(); + while (iterator.HasNext()) { + Device* device = iterator.Next(); + if (!strcmp(device->Path(), path)) { + node->RemoveDevice(device); + delete device; + return B_OK; + } + } +#endif + + return B_ENTRY_NOT_FOUND; +} + + +static status_t +get_attr_uint8(const device_node* node, const char* name, uint8* _value, + bool recursive) +{ + if (node == NULL || name == NULL || _value == NULL) + return B_BAD_VALUE; + + device_attr_private* attr = find_attr(node, name, recursive, B_UINT8_TYPE); + if (attr == NULL) + return B_NAME_NOT_FOUND; + + *_value = attr->value.ui8; + return B_OK; +} + + +static status_t +get_attr_uint16(const device_node* node, const char* name, uint16* _value, + bool recursive) +{ + if (node == NULL || name == NULL || _value == NULL) + return B_BAD_VALUE; + + device_attr_private* attr = find_attr(node, name, recursive, B_UINT16_TYPE); + if (attr == NULL) + return B_NAME_NOT_FOUND; + + *_value = attr->value.ui16; + return B_OK; +} + + +static status_t +get_attr_uint32(const device_node* node, const char* name, uint32* _value, + bool recursive) +{ + if (node == NULL || name == NULL || _value == NULL) + return B_BAD_VALUE; + + device_attr_private* attr = find_attr(node, name, recursive, B_UINT32_TYPE); + if (attr == NULL) + return B_NAME_NOT_FOUND; + + *_value = attr->value.ui32; + return B_OK; +} + + +static status_t +get_attr_uint64(const device_node* node, const char* name, + uint64* _value, bool recursive) +{ + if (node == NULL || name == NULL || _value == NULL) + return B_BAD_VALUE; + + device_attr_private* attr = find_attr(node, name, recursive, B_UINT64_TYPE); + if (attr == NULL) + return B_NAME_NOT_FOUND; + + *_value = attr->value.ui64; + return B_OK; +} + + +static status_t +get_attr_string(const device_node* node, const char* name, + const char** _value, bool recursive) +{ + if (node == NULL || name == NULL || _value == NULL) + return B_BAD_VALUE; + + device_attr_private* attr = find_attr(node, name, recursive, B_STRING_TYPE); + if (attr == NULL) + return B_NAME_NOT_FOUND; + + *_value = attr->value.string; + return B_OK; +} + + +static status_t +get_attr_raw(const device_node* node, const char* name, const void** _data, + size_t* _length, bool recursive) +{ + if (node == NULL || name == NULL || (_data == NULL && _length == NULL)) + return B_BAD_VALUE; + + device_attr_private* attr = find_attr(node, name, recursive, B_RAW_TYPE); + if (attr == NULL) + return B_NAME_NOT_FOUND; + + if (_data != NULL) + *_data = attr->value.raw.data; + if (_length != NULL) + *_length = attr->value.raw.length; + return B_OK; +} + + +static status_t +get_next_attr(device_node* node, device_attr** _attr) +{ + if (node == NULL) + return B_BAD_VALUE; + + device_attr_private* next; + device_attr_private* attr = *(device_attr_private**)_attr; + + if (attr != NULL) { + // next attribute + next = attr->GetDoublyLinkedListLink()->next; + } else { + // first attribute + next = node->Attributes().First(); + } + + *_attr = next; + + return next ? B_OK : B_ENTRY_NOT_FOUND; +} + + +struct device_manager_info gDeviceManagerModule = { + { + B_DEVICE_MANAGER_MODULE_NAME, + 0, + NULL + }, + + // device nodes + rescan_node, + register_node, + unregister_node, + get_driver, + get_root_node, + get_next_child_node, + get_parent_node, + put_node, + + // devices + publish_device, + unpublish_device, + + // I/O resources + + // ID generator + dm_create_id, + dm_free_id, + + // attributes + get_attr_uint8, + get_attr_uint16, + get_attr_uint32, + get_attr_uint64, + get_attr_string, + get_attr_raw, + get_next_attr, +}; + + +// #pragma mark - device_attr + + +device_attr_private::device_attr_private() +{ + name = NULL; + type = 0; + value.raw.data = NULL; + value.raw.length = 0; +} + + +device_attr_private::device_attr_private(const device_attr& attr) +{ + CopyFrom(attr); +} + + +device_attr_private::~device_attr_private() +{ + _Unset(); +} + + +status_t +device_attr_private::InitCheck() +{ + return name != NULL ? B_OK : B_NO_INIT; +} + + +status_t +device_attr_private::CopyFrom(const device_attr& attr) +{ + name = strdup(attr.name); + if (name == NULL) + return B_NO_MEMORY; + + type = attr.type; + + switch (type) { + case B_UINT8_TYPE: + case B_UINT16_TYPE: + case B_UINT32_TYPE: + case B_UINT64_TYPE: + value.ui64 = attr.value.ui64; + break; + + case B_STRING_TYPE: + if (attr.value.string != NULL) { + value.string = strdup(attr.value.string); + if (value.string == NULL) { + _Unset(); + return B_NO_MEMORY; + } + } else + value.string = NULL; + break; + + case B_RAW_TYPE: + value.raw.data = malloc(attr.value.raw.length); + if (value.raw.data == NULL) { + _Unset(); + return B_NO_MEMORY; + } + + value.raw.length = attr.value.raw.length; + memcpy((void*)value.raw.data, attr.value.raw.data, + attr.value.raw.length); + break; + + default: + return B_BAD_VALUE; + } + + return B_OK; +} + + +void +device_attr_private::_Unset() +{ + if (type == B_STRING_TYPE) + free((char*)value.string); + else if (type == B_RAW_TYPE) + free((void*)value.raw.data); + + free((char*)name); + + name = NULL; + value.raw.data = NULL; + value.raw.length = 0; +} + + +/*static*/ int +device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB) +{ + if (attrA->type != attrB->type) + return -1; + + switch (attrA->type) { + case B_UINT8_TYPE: + return (int)attrA->value.ui8 - (int)attrB->value.ui8; + + case B_UINT16_TYPE: + return (int)attrA->value.ui16 - (int)attrB->value.ui16; + + case B_UINT32_TYPE: + if (attrA->value.ui32 > attrB->value.ui32) + return 1; + if (attrA->value.ui32 < attrB->value.ui32) + return -1; + return 0; + + case B_UINT64_TYPE: + if (attrA->value.ui64 > attrB->value.ui64) + return 1; + if (attrA->value.ui64 < attrB->value.ui64) + return -1; + return 0; + + case B_STRING_TYPE: + return strcmp(attrA->value.string, attrB->value.string); + + case B_RAW_TYPE: + if (attrA->value.raw.length != attrB->value.raw.length) + return -1; + + return memcmp(attrA->value.raw.data, attrB->value.raw.data, + attrA->value.raw.length); + } + + return -1; +} + + +// #pragma mark - Device + + +Device::Device(device_node* node, const char* moduleName) +{ + fNode = node; + fModuleName = strdup(moduleName); +} + + +Device::~Device() +{ + free((char*)fModuleName); +} + + +status_t +Device::InitCheck() const +{ + return fModuleName != NULL ? B_OK : B_NO_MEMORY; +} + + +status_t +Device::InitDevice() +{ + if ((fNode->Flags() & NODE_FLAG_DEVICE_REMOVED) != 0) { + // TODO: maybe the device should be unlinked in devfs, too + return ENODEV; + } + if ((fNode->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) != 0) + return B_BUSY; + + if (fInitialized++ > 0) { + fNode->InitDriver(); + // acquire another reference to our parent as well + return B_OK; + } + + status_t status = get_module(ModuleName(), (module_info**)&fDeviceModule); + if (status == B_OK) { + // our parent always has to be initialized + status = fNode->InitDriver(); + } + if (status < B_OK) { + fInitialized--; + return status; + } + + if (Module()->init_device != NULL) + status = Module()->init_device(fNode->DriverData(), &fDeviceData); + + if (status < B_OK) { + fNode->UninitDriver(); + fInitialized--; + + put_module(ModuleName()); + fDeviceModule = NULL; + fDeviceData = NULL; + } + + return status; +} + + +void +Device::UninitDevice() +{ + if (fInitialized-- > 1) { + fNode->UninitDriver(); + return; + } + + TRACE(("uninit driver for node %p\n", this)); + + if (Module()->uninit_device != NULL) + Module()->uninit_device(fDeviceData); + + fDeviceModule = NULL; + fDeviceData = NULL; + + put_module(ModuleName()); + + fNode->UninitDriver(); +} + + +// #pragma mark - device_node + + +device_node::device_node(const char* moduleName, const device_attr* attrs) +{ + fModuleName = strdup(moduleName); + if (fModuleName == NULL) + return; + + fParent = NULL; + fRefCount = 1; + fInitialized = 0; + fRegistered = false; + fFlags = 0; + fSupportsParent = 0.0; + fLastUpdateCycle = 0; + fDriver = NULL; + fDriverData = NULL; + + // copy attributes + + while (attrs != NULL && attrs->name != NULL) { + device_attr_private* attr + = new(std::nothrow) device_attr_private(*attrs); + if (attr == NULL) + break; + + fAttributes.Add(attr); + attrs++; + } + + get_attr_uint32(this, B_DEVICE_FLAGS, &fFlags, false); + fFlags &= NODE_FLAG_PUBLIC_MASK; +} + + +device_node::~device_node() +{ + TRACE(("delete node %p\n", this)); + ASSERT(DriverModule() == NULL); + + if (Parent() != NULL) { + if ((fFlags & NODE_FLAG_OBSOLETE_DRIVER) != 0) { + // This driver has been obsoleted; another driver has been waiting + // for us - make it available + Parent()->_ReleaseWaiting(); + } + Parent()->RemoveChild(this); + } + + // Delete children + NodeList::Iterator nodeIterator = fChildren.GetIterator(); + while (nodeIterator.HasNext()) { + device_node* child = nodeIterator.Next(); + nodeIterator.Remove(); + delete child; + } + + // Delete devices + DeviceList::Iterator deviceIterator = fDevices.GetIterator(); + while (deviceIterator.HasNext()) { + Device* device = deviceIterator.Next(); + deviceIterator.Remove(); + // TODO: unpublish! + delete device; + } + + // Delete attributes + AttributeList::Iterator attrIterator = fAttributes.GetIterator(); + while (attrIterator.HasNext()) { + device_attr_private* attr = attrIterator.Next(); + attrIterator.Remove(); + delete attr; + } + + // Delete resources + ResourceList::Iterator resourceIterator = fResources.GetIterator(); + while (resourceIterator.HasNext()) { + io_resource_private* resource = resourceIterator.Next(); + resourceIterator.Remove(); + delete resource; + } + + free((char*)fModuleName); +} + + +status_t +device_node::InitCheck() const +{ + return fModuleName != NULL ? B_OK : B_NO_MEMORY; +} + + +status_t +device_node::AcquireResources(const io_resource* resources) +{ + if (resources == NULL) + return B_OK; + + for (uint32 i = 0; resources[i].type != 0; i++) { + io_resource_private* resource = new(std::nothrow) io_resource_private; + if (resource == NULL) + return B_NO_MEMORY; + + status_t status = resource->Acquire(resources[i]); + if (status != B_OK) { + delete resource; + return status; + } + + fResources.Add(resource); + } + + return B_OK; +} + + +status_t +device_node::InitDriver() +{ + if (fInitialized++ > 0) { + if (Parent() != NULL) { + Parent()->InitDriver(); + // acquire another reference to our parent as well + } + Acquire(); + return B_OK; + } + + status_t status = get_module(ModuleName(), (module_info**)&fDriver); + if (status == B_OK && Parent() != NULL) { + // our parent always has to be initialized + status = Parent()->InitDriver(); + } + if (status < B_OK) { + fInitialized--; + return status; + } + + if (fDriver->init_driver != NULL) + status = fDriver->init_driver(this, &fDriverData); + + if (status < B_OK) { + if (Parent() != NULL) + Parent()->UninitDriver(); + fInitialized--; + + put_module(ModuleName()); + fDriver = NULL; + fDriverData = NULL; + return status; + } + + Acquire(); + return B_OK; +} + + +bool +device_node::UninitDriver() +{ + if (fInitialized-- > 1) { + if (Parent() != NULL) + Parent()->UninitDriver(); + Release(); + return false; + } + + TRACE(("uninit driver for node %p\n", this)); + + if (fDriver->uninit_driver != NULL) + fDriver->uninit_driver(fDriverData); + + fDriver = NULL; + fDriverData = NULL; + + put_module(ModuleName()); + + if (Parent() != NULL) + Parent()->UninitDriver(); + Release(); + + return true; +} + + +void +device_node::AddChild(device_node* node) +{ + // we must not be destroyed as long as we have children + Acquire(); + node->fParent = this; + fChildren.Add(node); +} + + +void +device_node::RemoveChild(device_node* node) +{ + node->fParent = NULL; + fChildren.Remove(node); + Release(); +} + + +/*! Registers this node, and all of its children that have to be registered. + Also initializes the driver and keeps it that way on return in case + it returns successfully. +*/ +status_t +device_node::Register(device_node* parent) +{ + // make it public + if (parent != NULL) + parent->AddChild(this); + else + sRootNode = this; + + status_t status = InitDriver(); + if (status != B_OK) + return status; + + if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) { + // We keep this driver loaded by having it always initialized + InitDriver(); + } + + fFlags |= NODE_FLAG_REGISTER_INITIALIZED; + // We don't uninitialize the driver - this is done by the caller + // in order to save reinitializing during driver loading. + + uint32 registered; + status = _RegisterFixed(registered); + if (status != B_OK) { + UninitUnusedDriver(); + return status; + } + if (registered > 0) { + fRegistered = true; + return B_OK; + } + + // Register the children the driver wants + + if (DriverModule()->register_child_devices != NULL) { + status = DriverModule()->register_child_devices(DriverData()); + if (status != B_OK) { + UninitUnusedDriver(); + return status; + } + + if (!fChildren.IsEmpty()) { + fRegistered = true; + return B_OK; + } + } + + // Register all possible child device nodes + + status = _RegisterDynamic(); + if (status == B_OK) + fRegistered = true; + else + UninitUnusedDriver(); + + return status; +} + + +/*! Registers any children that are identified via the B_DRIVER_FIXED_CHILD + attribute. + If any of these children cannot be registered, this call will fail (we + don't remove children we already registered up to this point in this case). +*/ +status_t +device_node::_RegisterFixed(uint32& registered) +{ + AttributeList::Iterator iterator = fAttributes.GetIterator(); + registered = 0; + + while (iterator.HasNext()) { + device_attr_private* attr = iterator.Next(); + if (strcmp(attr->name, B_DEVICE_FIXED_CHILD)) + continue; + + driver_module_info* driver; + status_t status = get_module(attr->value.string, + (module_info**)&driver); + if (status != B_OK) { + TRACE(("register fixed child %s failed: %s\n", attr->value.string, + strerror(status))); + return status; + } + + if (driver->register_device != NULL) { + status = driver->register_device(this); + if (status == B_OK) + registered++; + } + + put_module(attr->value.string); + + if (status != B_OK) + return status; + } + + return B_OK; +} + + +status_t +device_node::_AddPath(Stack& stack, const char* basePath, + const char* subPath) +{ + KPath* path = new(std::nothrow) KPath; + if (path == NULL) + return B_NO_MEMORY; + + status_t status = path->SetTo(basePath); + if (status == B_OK && subPath != NULL && subPath[0]) + status = path->Append(subPath); + if (status == B_OK) + status = stack.Push(path); + + if (status != B_OK) + delete path; + + return status; +} + + +status_t +device_node::_GetNextDriverPath(void*& cookie, KPath& _path) +{ + Stack* stack = NULL; + + if (cookie == NULL) { + // find all paths and add them + stack = new(std::nothrow) Stack(); + if (stack == NULL) + return B_NO_MEMORY; + + StackDeleter stackDeleter(stack); + uint16 type = 0; + uint16 subType = 0; + uint16 interface = 0; + get_attr_uint16(this, B_DEVICE_TYPE, &type, false); + get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false); + get_attr_uint16(this, B_DEVICE_INTERFACE, &interface, false); + + // TODO: maybe make this extendible via settings file? + switch (type) { + case PCI_mass_storage: + switch (subType) { + case PCI_scsi: + _AddPath(*stack, "busses", "scsi"); + break; + case PCI_ide: + _AddPath(*stack, "busses", "ide"); + break; + case PCI_sata: + _AddPath(*stack, "busses", "sata"); + break; + default: + _AddPath(*stack, "busses", "disk"); + break; + } + break; + case PCI_serial_bus: + switch (subType) { + case PCI_firewire: + _AddPath(*stack, "busses", "firewire"); + break; + case PCI_usb: + _AddPath(*stack, "busses", "usb"); + break; + default: + _AddPath(*stack, "busses"); + break; + } + break; + case PCI_network: + _AddPath(*stack, "drivers", "net"); + break; + case PCI_display: + _AddPath(*stack, "drivers", "graphics"); + break; + case PCI_multimedia: + switch (subType) { + case PCI_audio: + case PCI_hd_audio: + _AddPath(*stack, "drivers", "audio"); + break; + case PCI_video: + _AddPath(*stack, "drivers", "video"); + break; + default: + _AddPath(*stack, "drivers"); + break; + } + break; + default: + if (sRootNode == this) { + _AddPath(*stack, "busses/pci"); + _AddPath(*stack, "bus_managers"); + } else + _AddPath(*stack, "drivers"); + break; + } + + stackDeleter.Detach(); + + cookie = (void*)stack; + } else + stack = static_cast*>(cookie); + + KPath* path; + if (stack->Pop(&path)) { + _path.Adopt(*path); + delete path; + return B_OK; + } + + delete stack; + return B_ENTRY_NOT_FOUND; +} + + +status_t +device_node::_GetNextDriver(void* list, driver_module_info*& driver) +{ + while (true) { + char name[B_FILE_NAME_LENGTH]; + size_t nameLength = sizeof(name); + + status_t status = read_next_module_name(list, name, &nameLength); + if (status != B_OK) + return status; + + if (!strcmp(fModuleName, name)) + continue; + + if (get_module(name, (module_info**)&driver) != B_OK) + continue; + + if (driver->supports_device == NULL + || driver->register_device == NULL) { + put_module(name); + continue; + } + + return B_OK; + } +} + + +status_t +device_node::_FindBestDriver(const char* path, driver_module_info*& bestDriver, + float& bestSupport, device_node* previous) +{ + if (bestDriver == NULL) + bestSupport = previous != NULL ? previous->fSupportsParent : 0.0f; + + void* list = open_module_list_etc(path, "driver_v1"); + driver_module_info* driver; + while (_GetNextDriver(list, driver) == B_OK) { + if (previous != NULL && driver == previous->DriverModule()) { + put_module(driver->info.name); + continue; + } + + float support = driver->supports_device(this); + if (support > bestSupport) { + if (bestDriver != NULL) + put_module(bestDriver->info.name); + + bestDriver = driver; + bestSupport = support; + continue; + // keep reference to best module around + } + + put_module(driver->info.name); + } + close_module_list(list); + + return bestDriver != NULL ? B_OK : B_ENTRY_NOT_FOUND; +} + + +status_t +device_node::_RegisterPath(const char* path) +{ + void* list = open_module_list_etc(path, "driver_v1"); + driver_module_info* driver; + uint32 count = 0; + + while (_GetNextDriver(list, driver) == B_OK) { + float support = driver->supports_device(this); + if (support > 0.0) { + TRACE((" register module \"%s\", support %f\n", driver->info.name, + support)); + if (driver->register_device(this) == B_OK) + count++; + } + + put_module(driver->info.name); + } + close_module_list(list); + + return count > 0 ? B_OK : B_ENTRY_NOT_FOUND; +} + + +bool +device_node::_AlwaysRegisterDynamic() +{ + uint16 type = 0; + uint16 subType = 0; + get_attr_uint16(this, B_DEVICE_TYPE, &type, false); + get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false); + + return type == PCI_serial_bus || type == PCI_bridge; + // TODO: we may want to be a bit more specific in the future +} + + +status_t +device_node::_RegisterDynamic(device_node* previous) +{ + // If this is not a bus, we don't have to scan it + if (find_attr(this, B_DEVICE_BUS, false, B_STRING_TYPE) == NULL) + return B_OK; + + // If we're not being probed, we honour the B_FIND_CHILD_ON_DEMAND + // requirements + if (!IsProbed() && (fFlags & B_FIND_CHILD_ON_DEMAND) != 0 + && !_AlwaysRegisterDynamic()) + return B_OK; + + KPath path; + + if ((fFlags & B_FIND_MULTIPLE_CHILDREN) == 0) { + // find the one driver + driver_module_info* bestDriver = NULL; + float bestSupport = 0.0; + void* cookie = NULL; + + while (_GetNextDriverPath(cookie, path) == B_OK) { + _FindBestDriver(path.Path(), bestDriver, bestSupport, previous); + } + + if (bestDriver != NULL) { + TRACE((" register best module \"%s\", support %f\n", + bestDriver->info.name, bestSupport)); + if (bestDriver->register_device(this) == B_OK) { + // There can only be one node of this driver + // (usually only one at all, but there might be a new driver + // "waiting" for its turn) + device_node* child = FindChild(bestDriver->info.name); + if (child != NULL) { + child->fSupportsParent = bestSupport; + if (previous != NULL) { + previous->fFlags |= NODE_FLAG_OBSOLETE_DRIVER; + previous->Release(); + child->fFlags |= NODE_FLAG_WAITING_FOR_DRIVER; + } + } + // TODO: if this fails, we could try the second best driver, + // and so on... + } + put_module(bestDriver->info.name); + } + } else { + // register all drivers that match + void* cookie = NULL; + while (_GetNextDriverPath(cookie, path) == B_OK) { + _RegisterPath(path.Path()); + } + } + + return B_OK; +} + + +void +device_node::_ReleaseWaiting() +{ + NodeList::Iterator iterator = fChildren.GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + child->fFlags &= ~NODE_FLAG_WAITING_FOR_DRIVER; + } +} + + +status_t +device_node::_RemoveChildren() +{ + NodeList::Iterator iterator = fChildren.GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + child->Release(); + } + + return fChildren.IsEmpty() ? B_OK : B_BUSY; +} + + +device_node* +device_node::_FindCurrentChild() +{ + NodeList::Iterator iterator = fChildren.GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + if ((child->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) == 0) + return child; + } + + return NULL; +} + + +status_t +device_node::_Rescan() +{ + device_node* previous = NULL; + + if (IsProbed() && !fChildren.IsEmpty() + && (fFlags & (B_FIND_CHILD_ON_DEMAND | B_FIND_MULTIPLE_CHILDREN)) + == B_FIND_CHILD_ON_DEMAND) { + // We already have a driver that claims this node; remove all + // (unused) nodes, and evaluate it again + _RemoveChildren(); + + previous = _FindCurrentChild(); + if (previous != NULL) { + // This driver is still active - give it back the reference + // that was stolen by _RemoveChildren() - _RegisterDynamic() + // will release it, if it really isn't needed anymore + previous->Acquire(); + } + } + + return _RegisterDynamic(previous); +} + + +status_t +device_node::Probe(const char* devicePath, uint32 updateCycle) +{ + if ((fFlags & NODE_FLAG_DEVICE_REMOVED) != 0 + || updateCycle == fLastUpdateCycle) + return B_OK; + + status_t status = InitDriver(); + if (status < B_OK) + return status; + + MethodDeleter uninit(this, + &device_node::UninitDriver); + + uint16 type = 0; + uint16 subType = 0; + if (get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK + && get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false) == B_OK) { + // Check if this node matches the device path + // TODO: maybe make this extendible via settings file? + bool matches = false; + if (!strcmp(devicePath, "disk")) { + matches = type == PCI_mass_storage; + } else if (!strcmp(devicePath, "audio")) { + matches = type == PCI_multimedia + && (subType == PCI_audio || subType == PCI_hd_audio); + } else if (!strcmp(devicePath, "net")) { + matches = type == PCI_network; + } else if (!strcmp(devicePath, "graphics")) { + matches = type == PCI_display; + } else if (!strcmp(devicePath, "video")) { + matches = type == PCI_multimedia && subType == PCI_video; + } + + if (matches) { + fLastUpdateCycle = updateCycle; + // This node will be probed in this update cycle + + return _Rescan(); + } + + return B_OK; + } + + NodeList::Iterator iterator = fChildren.GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + status = child->Probe(devicePath, updateCycle); + if (status != B_OK) + return status; + } + + return B_OK; +} + + +status_t +device_node::Rescan() +{ + // If this child has been probed already, probe it again + status_t status = _Rescan(); + if (status != B_OK) + return status; + + NodeList::Iterator iterator = fChildren.GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + status = child->Rescan(); + if (status != B_OK) + return status; + } + + return B_OK; +} + + +/*! Uninitializes all temporary references to the driver. The registration + process keeps the driver initialized to optimize the startup procedure; + this function gives this reference away again. +*/ +void +device_node::UninitUnusedDriver() +{ + // First, we need to go to the leaf, and go back from there + + NodeList::Iterator iterator = fChildren.GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + child->UninitUnusedDriver(); + } + + if (!IsInitialized() + || (fFlags & NODE_FLAG_REGISTER_INITIALIZED) == 0) + return; + + fFlags &= ~NODE_FLAG_REGISTER_INITIALIZED; + + UninitDriver(); +} + + +/*! Calls device_removed() on this node and all of its children - starting + with the deepest and last child. + It will also remove the one reference that every node gets on its creation. +*/ +void +device_node::DeviceRemoved() +{ + // notify children + NodeList::ConstIterator iterator = Children().GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + child->DeviceRemoved(); + } + + // notify devices + DeviceList::ConstIterator deviceIterator = Devices().GetIterator(); + while (deviceIterator.HasNext()) { + Device* device = deviceIterator.Next(); + + if (device->Module() != NULL + && device->Module()->device_removed != NULL) + device->Module()->device_removed(device->Data()); + } + + fFlags |= NODE_FLAG_DEVICE_REMOVED; + + if (IsInitialized() && DriverModule()->device_removed != NULL) + DriverModule()->device_removed(this); + + if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) { + // There is no point in keeping this driver loaded when its device + // is gone + UninitDriver(); + } + + UninitUnusedDriver(); + Release(); +} + + +void +device_node::Acquire() +{ + atomic_add(&fRefCount, 1); +} + + +bool +device_node::Release() +{ + if (atomic_add(&fRefCount, -1) > 1) + return false; + + delete this; + return true; +} + + +void +device_node::AddDevice(Device* device) +{ + fDevices.Add(device); +} + + +void +device_node::RemoveDevice(Device* device) +{ + fDevices.Remove(device); +} + + +int +device_node::CompareTo(const device_attr* attributes) const +{ + if (attributes == NULL) + return -1; + + for (; attributes->name != NULL; attributes++) { + // find corresponding attribute + AttributeList::ConstIterator iterator = Attributes().GetIterator(); + device_attr_private* attr = NULL; + while (iterator.HasNext()) { + attr = iterator.Next(); + + if (!strcmp(attr->name, attributes->name)) + break; + } + if (!iterator.HasNext()) + return -1; + + int compare = device_attr_private::Compare(attr, attributes); + if (compare != 0) + return compare; + } + + return 0; +} + + +device_node* +device_node::FindChild(const device_attr* attributes) const +{ + if (attributes == NULL) + return NULL; + + NodeList::ConstIterator iterator = Children().GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + // ignore nodes that are pending to be removed + if ((child->Flags() & NODE_FLAG_DEVICE_REMOVED) == 0 + && !child->CompareTo(attributes)) + return child; + } + + return NULL; +} + + +device_node* +device_node::FindChild(const char* moduleName) const +{ + if (moduleName == NULL) + return NULL; + + NodeList::ConstIterator iterator = Children().GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + if (!strcmp(child->ModuleName(), moduleName)) + return child; + } + + return NULL; +} + + +void +device_node::Dump(int32 level = 0) +{ + put_level(level); + dprintf("(%ld) @%p \"%s\" (ref %ld, init %ld, module %p, data %p)\n", level, + this, ModuleName(), fRefCount, fInitialized, DriverModule(), + DriverData()); + + AttributeList::Iterator attribute = Attributes().GetIterator(); + while (attribute.HasNext()) { + dump_attribute(attribute.Next(), level); + } + + DeviceList::Iterator deviceIterator = fDevices.GetIterator(); + while (deviceIterator.HasNext()) { + Device* device = deviceIterator.Next(); + put_level(level); + dprintf("device: %s, %p\n", device->ModuleName(), device->Data()); + } + + NodeList::ConstIterator iterator = Children().GetIterator(); + while (iterator.HasNext()) { + iterator.Next()->Dump(level + 1); + } +} + + +// #pragma mark - root node + + +static void +init_root_node(void) +{ + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}}, + {B_DEVICE_BUS, B_STRING_TYPE, {string: "root"}}, + {B_DEVICE_FLAGS, B_UINT32_TYPE, + {ui32: B_FIND_MULTIPLE_CHILDREN | B_KEEP_DRIVER_LOADED }}, + {NULL} + }; + + if (register_node(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, NULL) + != B_OK) { + dprintf("Cannot register Devices Root Node\n"); + } +} + + +driver_module_info gDeviceRootModule = { + { + DEVICE_MANAGER_ROOT_NAME, + 0, + NULL, + }, + NULL +}; + + +// #pragma mark - private kernel API + + +status_t +device_manager_probe(const char* path, uint32 updateCycle) +{ + TRACE(("device_manager_probe(\"%s\")\n", path)); + RecursiveLocker _(sLock); + + // first, publish directories in the driver directory + publish_directories(path); + + return sRootNode->Probe(path, updateCycle); +} + + +status_t +device_manager_init(struct kernel_args* args) +{ + TRACE(("device manager init\n")); + + dm_init_id_generator(); + dm_init_io_resources(); + + recursive_lock_init(&sLock, "device manager"); + init_root_node(); + +#ifdef TRACE_DEVICE_MANAGER + sRootNode->Dump(); +#endif + + add_debugger_command("dm_tree", &dump_device_nodes, + "dump device node tree"); + register_generic_syscall(DEVICE_MANAGER_SYSCALLS, control_device_manager, + 1, 0); + return B_OK; +} + + +status_t +device_manager_init_post_modules(struct kernel_args* args) +{ + return sRootNode->Rescan(); +} + diff --git a/src/system/kernel/device_manager/device_manager_private.h b/src/system/kernel/device_manager/device_manager_private.h index 44574a57d3..b18284d937 100644 --- a/src/system/kernel/device_manager/device_manager_private.h +++ b/src/system/kernel/device_manager/device_manager_private.h @@ -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 -#include - -#include - -#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 diff --git a/src/system/kernel/device_manager/id_generator.c b/src/system/kernel/device_manager/id_generator.cpp similarity index 51% rename from src/system/kernel/device_manager/id_generator.c rename to src/system/kernel/device_manager/id_generator.cpp index a207983352..2a5bed3ffe 100644 --- a/src/system/kernel/device_manager/id_generator.c +++ b/src/system/kernel/device_manager/id_generator.cpp @@ -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 -#include +#include "id_generator.h" +#include #include #include +#include + +#include +#include + //#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(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 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 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; } - diff --git a/src/system/kernel/device_manager/id_generator.h b/src/system/kernel/device_manager/id_generator.h new file mode 100644 index 0000000000..b8fdd2a0ee --- /dev/null +++ b/src/system/kernel/device_manager/id_generator.h @@ -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 + + +#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 */ diff --git a/src/system/kernel/device_manager/io_resources.c b/src/system/kernel/device_manager/io_resources.c deleted file mode 100644 index 008b329eca..0000000000 --- a/src/system/kernel/device_manager/io_resources.c +++ /dev/null @@ -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 - -#include -#include - - -//#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; -} - diff --git a/src/system/kernel/device_manager/io_resources.cpp b/src/system/kernel/device_manager/io_resources.cpp new file mode 100644 index 0000000000..e91c40d31a --- /dev/null +++ b/src/system/kernel/device_manager/io_resources.cpp @@ -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 +#include + + +//#define TRACE_IO_RESOURCES +#ifdef TRACE_IO_RESOURCES +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +typedef DoublyLinkedList > 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; +} diff --git a/src/system/kernel/device_manager/io_resources.h b/src/system/kernel/device_manager/io_resources.h new file mode 100644 index 0000000000..2091b0e17a --- /dev/null +++ b/src/system/kernel/device_manager/io_resources.h @@ -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 + +#include + + +struct io_resource_private : io_resource, + DoublyLinkedListLinkImpl { + 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 fTypeLink; +}; + +typedef DoublyLinkedList ResourceList; + + +#ifdef __cplusplus +extern "C" { +#endif + +void dm_init_io_resources(void); + +#ifdef __cplusplus +} +#endif + +#endif /* IO_RESOURCES_H */ diff --git a/src/system/kernel/device_manager/legacy_drivers.cpp b/src/system/kernel/device_manager/legacy_drivers.cpp new file mode 100644 index 0000000000..db7b94fdc2 --- /dev/null +++ b/src/system/kernel/device_manager/legacy_drivers.cpp @@ -0,0 +1,1445 @@ +/* + * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "legacy_drivers.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BaseDevice.h" +#include "devfs_private.h" + + +//#define TRACE_LEGACY_DRIVERS +#ifdef TRACE_LEGACY_DRIVERS +# define TRACE(x) dprintf x +#else +# define TRACE(x) +#endif + +#define DRIVER_HASH_SIZE 16 + +struct legacy_driver; + +class LegacyDevice : public BaseDevice, + public DoublyLinkedListLinkImpl { +public: + LegacyDevice(legacy_driver* driver, + const char* path, device_hooks* hooks); + virtual ~LegacyDevice(); + + status_t InitCheck() const; + + virtual status_t InitDevice(); + virtual void UninitDevice(); + + void SetHooks(device_hooks* hooks); + + legacy_driver* Driver() const { return fDriver; } + const char* Path() const { return fPath; } + device_hooks* Hooks() const { return fHooks; } + + virtual status_t Open(const char* path, int openMode, + void** _cookie); + virtual status_t Select(void* cookie, uint8 event, selectsync* sync); + +private: + legacy_driver* fDriver; + const char* fPath; + device_hooks* fHooks; +}; + +typedef DoublyLinkedList DeviceList; + +struct legacy_driver { + legacy_driver* next; + const char* path; + const char* name; + dev_t device; + ino_t node; + time_t last_modified; + image_id image; + uint32 devices_published; + uint32 devices_used; + bool binary_updated; + int32 priority; + DeviceList devices; + + // driver image information + int32 api_version; + device_hooks* (*find_device)(const char *); + const char** (*publish_devices)(void); + status_t (*uninit_driver)(void); + status_t (*uninit_hardware)(void); +}; + +struct path_entry : DoublyLinkedListLinkImpl { + char path[B_PATH_NAME_LENGTH]; +}; + +struct driver_entry : public DoublyLinkedListLinkImpl { + char* path; + dev_t device; + ino_t node; + int32 busses; +}; + +typedef DoublyLinkedList DriverEntryList; + +struct directory_node_entry { + HashTableLink link; + ino_t node; +}; + +struct DirectoryNodeHashDefinition { + typedef ino_t* KeyType; + typedef directory_node_entry ValueType; + + size_t HashKey(ino_t* key) const + { return _Hash(*key); } + size_t Hash(directory_node_entry* entry) const + { return _Hash(entry->node); } + bool Compare(ino_t* key, directory_node_entry* entry) const + { return *key == entry->node; } + HashTableLink* + GetLink(directory_node_entry* entry) const + { return &entry->link; } + + uint32 _Hash(ino_t node) const + { return (uint32)(node >> 32) + (uint32)node; } +}; + +typedef OpenHashTable DirectoryNodeHash; + +class DirectoryIterator { +public: + DirectoryIterator(const char *path, + const char *subPath = NULL, bool recursive = false); + ~DirectoryIterator(); + + void SetTo(const char *path, const char *subPath = NULL, + bool recursive = false); + + status_t GetNext(KPath &path, struct stat &stat); + const char* CurrentName() const { return fCurrentName; } + + void Unset(); + void AddPath(const char *path, const char *subPath = NULL); + +private: + Stack fPaths; + bool fRecursive; + DIR* fDirectory; + KPath* fBasePath; + const char* fCurrentName; +}; + + +class DirectoryWatcher : public NotificationListener { +public: + DirectoryWatcher(); + virtual ~DirectoryWatcher(); + + virtual void EventOccured(NotificationService& service, + const KMessage* event); +}; + +class DriverWatcher : public NotificationListener { +public: + DriverWatcher(); + virtual ~DriverWatcher(); + + virtual void EventOccured(NotificationService& service, + const KMessage* event); +}; + +static status_t unload_driver(legacy_driver *driver); +static status_t load_driver(legacy_driver *driver); + + +static int32 sDefaultApiVersion = 1; +static hash_table* sDriverHash; +static DriverWatcher sDriverWatcher; +static int32 sDriverEvents; +static DoublyLinkedList sDriversToAdd; +static DirectoryWatcher sDirectoryWatcher; +static DirectoryNodeHash sDirectoryNodeHash; +static mutex sLock; +static bool sWatching; + + +// #pragma mark - driver private + + +static uint32 +driver_entry_hash(void *_driver, const void *_key, uint32 range) +{ + legacy_driver *driver = (legacy_driver *)_driver; + const char *key = (const char *)_key; + + if (driver != NULL) + return hash_hash_string(driver->name) % range; + + return hash_hash_string(key) % range; +} + + +static int +driver_entry_compare(void *_driver, const void *_key) +{ + legacy_driver *driver = (legacy_driver *)_driver; + const char *key = (const char *)_key; + + return strcmp(driver->name, key); +} + + +static LegacyDevice* +get_device_for_path(legacy_driver* driver, const char* path) +{ + DeviceList::Iterator iterator = driver->devices.GetIterator(); + while (iterator.HasNext()) { + LegacyDevice* device = iterator.Next(); + + if (!strcmp(device->Path(), path)) + return device; + } + + return NULL; +} + + +/*! Collects all published devices of a driver, compares them to what the + driver would publish now, and then publishes/unpublishes the devices + as needed. + If the driver does not publish any devices anymore, it is unloaded. +*/ +static status_t +republish_driver(legacy_driver* driver) +{ + if (driver->image < 0) { + // The driver is not yet loaded - go through the normal load procedure + return load_driver(driver); + } + + // build the list of currently present devices of this driver + DeviceList::Iterator iterator = driver->devices.GetIterator(); + DoublyLinkedList currentNodes; + while (iterator.HasNext()) { + LegacyDevice* device = iterator.Next(); + + path_entry* entry = new(std::nothrow) path_entry; + if (entry == NULL) { + while ((entry = currentNodes.RemoveHead())) + delete entry; + return B_NO_MEMORY; + } + + strlcpy(entry->path, device->Path(), sizeof(entry->path)); + currentNodes.Add(entry); + } + + // now ask the driver for it's currently published devices + const char **devicePaths = driver->publish_devices(); + + int32 exported = 0; + for (; devicePaths != NULL && devicePaths[0]; devicePaths++) { + bool present = false; + path_entry *entry = currentNodes.Head(); + while (entry) { + if (strncmp(entry->path, devicePaths[0], B_PATH_NAME_LENGTH) == 0) { + // this device was present before and still is -> no republish + currentNodes.Remove(entry); + delete entry; + exported++; + present = true; + break; + } + + entry = currentNodes.GetNext(entry); + } + + device_hooks *hooks = driver->find_device(devicePaths[0]); + if (hooks == NULL) + continue; + + if (present) { + // update hooks + LegacyDevice* device = get_device_for_path(driver, devicePaths[0]); + if (device != NULL) + device->SetHooks(hooks); + continue; + } + + // the device was not present before -> publish it now + TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0])); + LegacyDevice* device = new(std::nothrow) LegacyDevice(driver, + devicePaths[0], hooks); + if (device != NULL && device->InitCheck() == B_OK + && devfs_publish_device(devicePaths[0], device) == B_OK) { + driver->devices.Add(device); + exported++; + } else + delete device; + } + + // what's left in currentNodes was present but is not anymore -> unpublish + while (true) { + path_entry *entry = currentNodes.RemoveHead(); + if (entry == NULL) + break; + + TRACE(("devfs: unpublishing no more present \"%s\"\n", entry->path)); + LegacyDevice* device = get_device_for_path(driver, devicePaths[0]); + if (device != NULL) { + driver->devices.Remove(device); + delete device; + } + + devfs_unpublish_device(entry->path, true); + delete entry; + } + + if (exported == 0) { + TRACE(("devfs: driver \"%s\" does not publish any more nodes and is unloaded\n", driver->path)); + unload_driver(driver); + } + + return B_OK; +} + + +static status_t +load_driver(legacy_driver *driver) +{ + status_t (*init_hardware)(void); + status_t (*init_driver)(void); + const char **devicePaths; + int32 exported = 0; + status_t status; + + driver->binary_updated = false; + + // load the module + image_id image = driver->image; + if (image < 0) { + image = load_kernel_add_on(driver->path); + if (image < 0) + return image; + } + + // For a valid device driver the following exports are required + + int32 *apiVersion; + if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA, + (void **)&apiVersion) == B_OK) { +#if B_CUR_DRIVER_API_VERSION != 2 + // just in case someone decides to bump up the api version +#error Add checks here for new vs old api version! +#endif + if (*apiVersion > B_CUR_DRIVER_API_VERSION) { + dprintf("devfs: \"%s\" api_version %ld not handled\n", driver->name, + *apiVersion); + status = B_BAD_VALUE; + goto error1; + } + if (*apiVersion < 1) { + dprintf("devfs: \"%s\" api_version invalid\n", driver->name); + status = B_BAD_VALUE; + goto error1; + } + + driver->api_version = *apiVersion; + } else + dprintf("devfs: \"%s\" api_version missing\n", driver->name); + + if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT, + (void **)&driver->publish_devices) != B_OK + || get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT, + (void **)&driver->find_device) != B_OK) { + dprintf("devfs: \"%s\" mandatory driver symbol(s) missing!\n", + driver->name); + status = B_BAD_VALUE; + goto error1; + } + + // Init the driver + + if (get_image_symbol(image, "init_hardware", B_SYMBOL_TYPE_TEXT, + (void **)&init_hardware) == B_OK + && (status = init_hardware()) != B_OK) { + TRACE(("%s: init_hardware() failed: %s\n", driver->name, + strerror(status))); + status = ENXIO; + goto error1; + } + + if (get_image_symbol(image, "init_driver", B_SYMBOL_TYPE_TEXT, + (void **)&init_driver) == B_OK + && (status = init_driver()) != B_OK) { + TRACE(("%s: init_driver() failed: %s\n", driver->name, + strerror(status))); + status = ENXIO; + goto error2; + } + + // resolve and cache those for the driver unload code + if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT, + (void **)&driver->uninit_driver) != B_OK) + driver->uninit_driver = NULL; + if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT, + (void **)&driver->uninit_hardware) != B_OK) + driver->uninit_hardware = NULL; + + // The driver has successfully been initialized, now we can + // finally publish its device entries + + driver->image = image; + return republish_driver(driver); + +error3: + if (driver->uninit_driver) + driver->uninit_driver(); + +error2: + if (driver->uninit_hardware) + driver->uninit_hardware(); + +error1: + if (driver->image < 0) { + unload_kernel_add_on(image); + driver->image = status; + } + + return status; +} + + +static status_t +unload_driver(legacy_driver *driver) +{ + if (driver->image < 0) { + // driver is not currently loaded + return B_NO_INIT; + } + + if (driver->uninit_driver) + driver->uninit_driver(); + + if (driver->uninit_hardware) + driver->uninit_hardware(); + + unload_kernel_add_on(driver->image); + driver->image = -1; + driver->binary_updated = false; + driver->find_device = NULL; + driver->publish_devices = NULL; + driver->uninit_driver = NULL; + driver->uninit_hardware = NULL; + + return B_OK; +} + + +/*! Collects all devices belonging to the \a driver and unpublishs them. +*/ +static void +unpublish_driver(legacy_driver *driver) +{ + // Iterate through all nodes until all devices of this driver have + // been unpublished + +dprintf("IMPLEMENT unpublish_driver()!\n"); +#if 0 + while (driver->devices_published > 0) { + struct hash_iterator i; + hash_open(sDeviceFileSystem->vnode_hash, &i); + + while (true) { + devfs_vnode *vnode = (devfs_vnode *)hash_next( + sDeviceFileSystem->vnode_hash, &i); + if (vnode == NULL) + break; + + if (S_ISCHR(vnode->stream.type) + && vnode->stream.u.dev.driver == driver) { + void *dummy; + get_vnode(sDeviceFileSystem->volume, vnode->id, &dummy); + // We need to get/put the node, so that it is + // actually removed + + unpublish_node(sDeviceFileSystem, vnode, S_IFCHR); + put_vnode(sDeviceFileSystem->volume, vnode->id); + break; + } + } + + hash_close(sDeviceFileSystem->vnode_hash, &i, false); + } +#endif +} + + +static int32 +get_priority(const char* path) +{ + // TODO: would it be better to initialize a static structure here + // using find_directory()? + const directory_which whichPath[] = { + B_BEOS_DIRECTORY, + B_COMMON_DIRECTORY, + B_USER_DIRECTORY + }; + KPath pathBuffer; + + for (uint32 index = 0; index < sizeof(whichPath) / sizeof(whichPath[0]); + index++) { + if (find_directory(whichPath[index], gBootDevice, false, + pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { + pathBuffer.UnlockBuffer(); + if (!strncmp(pathBuffer.Path(), path, pathBuffer.BufferSize())) + return index; + } else + pathBuffer.UnlockBuffer(); + } + + return -1; +} + + +static const char * +get_leaf(const char *path) +{ + const char *name = strrchr(path, '/'); + if (name == NULL) + return path; + + return name + 1; +} + + +static legacy_driver * +find_driver(dev_t device, ino_t node) +{ + hash_iterator iterator; + hash_open(sDriverHash, &iterator); + legacy_driver *driver; + while (true) { + driver = (legacy_driver *)hash_next(sDriverHash, &iterator); + if (driver == NULL + || driver->device == device && driver->node == node) + break; + } + + hash_close(sDriverHash, &iterator, false); + return driver; +} + + +static status_t +add_driver(const char *path, image_id image) +{ + // see if we already know this driver + + struct stat stat; + if (image >= 0) { + // The image ID should be a small number and hopefully the boot FS + // doesn't use small negative values -- if it is inode based, we should + // be relatively safe. + stat.st_dev = -1; + stat.st_ino = -1; + } else { + if (::stat(path, &stat) != 0) + return errno; + } + + int32 priority = get_priority(path); + +// RecursiveLocker locker(&sDeviceFileSystem->lock); + MutexLocker _(sLock); + + legacy_driver *driver = (legacy_driver *)hash_lookup(sDriverHash, + get_leaf(path)); + if (driver != NULL) { + // we know this driver + // TODO: check if this driver is a different one and has precendence + // (ie. common supersedes system). + //dprintf("new driver has priority %ld, old %ld\n", priority, driver->priority); + if (priority >= driver->priority) { + driver->binary_updated = true; + return B_OK; + } + + // TODO: test for changes here and/or via node monitoring and reload + // the driver if necessary + if (driver->image < B_OK) + return driver->image; + + return B_OK; + } + + // we don't know this driver, create a new entry for it + + driver = (legacy_driver *)malloc(sizeof(legacy_driver)); + if (driver == NULL) + return B_NO_MEMORY; + + driver->path = strdup(path); + if (driver->path == NULL) { + free(driver); + return B_NO_MEMORY; + } + + driver->name = get_leaf(driver->path); + driver->device = stat.st_dev; + driver->node = stat.st_ino; + driver->image = image; + driver->last_modified = stat.st_mtime; + driver->devices_published = 0; + driver->devices_used = 0; + driver->binary_updated = false; + driver->priority = priority; + + driver->api_version = 1; + driver->find_device = NULL; + driver->publish_devices = NULL; + driver->uninit_driver = NULL; + driver->uninit_hardware = NULL; + new(&driver->devices) DeviceList; + + hash_insert(sDriverHash, driver); + if (stat.st_dev > 0) { + add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_STAT, + sDriverWatcher); + } + + // Even if loading the driver fails - its entry will stay with us + // so that we don't have to go through it again + return load_driver(driver); +} + + +/*! This is no longer part of the public kernel API, so we just export the + symbol +*/ +extern "C" status_t load_driver_symbols(const char *driverName); +status_t +load_driver_symbols(const char *driverName) +{ + // This is done globally for the whole kernel via the settings file. + // We don't have to do anything here. + + return B_OK; +} + + +static status_t +reload_driver(legacy_driver *driver) +{ + dprintf("devfs: reload driver \"%s\"\n", driver->name); + + unload_driver(driver); + + status_t status = load_driver(driver); + if (status < B_OK) + unpublish_driver(driver); + + return status; +} + + +static void +handle_driver_events(void *_fs, int /*iteration*/) +{ + struct devfs *fs = (devfs *)_fs; + + if (atomic_and(&sDriverEvents, 0) == 0) + return; + + // something happened, let's see what it was + +// RecursiveLocker locker(fs->lock); + MutexLocker locker(sLock); + + while (true) { + path_entry *path = sDriversToAdd.RemoveHead(); + if (path == NULL) + break; + + legacy_driver_add(path->path); + delete path; + } + + hash_iterator iterator; + hash_open(sDriverHash, &iterator); + legacy_driver *driver; + while (true) { + driver = (legacy_driver *)hash_next(sDriverHash, &iterator); + if (driver == NULL) + break; + if (!driver->binary_updated || driver->devices_used != 0) + continue; + + // try to reload the driver + reload_driver(driver); + } + + hash_close(sDriverHash, &iterator, false); +} + + +// #pragma mark - DriverWatcher + + +DriverWatcher::DriverWatcher() +{ +} + + +DriverWatcher::~DriverWatcher() +{ +} + + +void +DriverWatcher::EventOccured(NotificationService& service, + const KMessage* event) +{ + if (event->GetInt32("opcode", -1) != B_STAT_CHANGED + || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) + return; + + MutexLocker locker(sLock); + + legacy_driver* driver = find_driver(event->GetInt32("device", -1), + event->GetInt64("node", 0)); + if (driver == NULL) + return; + + driver->binary_updated = true; +//dprintf("%s: devices published %ld, used %ld\n", driver->name, driver->devices_published, driver->devices_used); + if (driver->devices_used == 0) { + // trigger a reload of the driver + atomic_add(&sDriverEvents, 1); + } else { + // driver is in use right now + dprintf("devfs: changed driver \"%s\" is still in use\n", driver->name); + } +} + + +static int +dump_driver(int argc, char** argv) +{ + if (argc < 2) { + // print list of all drivers + kprintf("address image used publ. pri name\n"); + hash_iterator iterator; + hash_open(sDriverHash, &iterator); + while (true) { + legacy_driver* driver = (legacy_driver*)hash_next(sDriverHash, + &iterator); + if (driver == NULL) + break; + + kprintf("%p %5ld %3ld %5ld %c %3ld %s\n", driver, + driver->image < 0 ? -1 : driver->image, + driver->devices_used, driver->devices_published, + driver->binary_updated ? 'U' : ' ', driver->priority, + driver->name); + } + + hash_close(sDriverHash, &iterator, false); + return 0; + } + + if (!strcmp(argv[1], "--help")) { + kprintf("usage: %s [name]\n", argv[0]); + return 0; + } + + legacy_driver* driver = (legacy_driver*)hash_lookup(sDriverHash, argv[1]); + if (driver == NULL) { + kprintf("Driver named \"%s\" not found.\n", argv[1]); + return 0; + } + + kprintf("DEVFS DRIVER: %p\n", driver); + kprintf(" name: %s\n", driver->name); + kprintf(" path: %s\n", driver->path); + kprintf(" image: %ld\n", driver->image); + kprintf(" device: %ld\n", driver->device); + kprintf(" node: %Ld\n", driver->node); + kprintf(" last modified: %ld\n", driver->last_modified); + kprintf(" devs used: %ld\n", driver->devices_used); + kprintf(" devs published: %ld\n", driver->devices_published); + kprintf(" binary updated: %d\n", driver->binary_updated); + kprintf(" priority: %ld\n", driver->priority); + kprintf(" api version: %ld\n", driver->api_version); + kprintf(" hooks: find_device %p, publish_devices %p\n" + " uninit_driver %p, uninit_hardware %p\n", + driver->find_device, driver->publish_devices, driver->uninit_driver, + driver->uninit_hardware); + + return 0; +} + + +// #pragma mark - + + +DirectoryIterator::DirectoryIterator(const char* path, const char* subPath, + bool recursive) + : + fDirectory(NULL), + fBasePath(NULL), + fCurrentName(NULL) +{ + SetTo(path, subPath, recursive); +} + + +DirectoryIterator::~DirectoryIterator() +{ + Unset(); +} + + +void +DirectoryIterator::SetTo(const char* path, const char* subPath, bool recursive) +{ + Unset(); + fRecursive = recursive; + + if (path == NULL) { + // add default paths + const directory_which whichPath[] = { + B_USER_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY + }; + KPath pathBuffer; + + bool disableUserAddOns = get_safemode_boolean( + B_SAFEMODE_DISABLE_USER_ADD_ONS, false); + + for (uint32 i = 0; i < sizeof(whichPath) / sizeof(whichPath[0]); i++) { + if (i < 2 && disableUserAddOns) + continue; + + if (find_directory(whichPath[i], gBootDevice, true, + pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { + pathBuffer.UnlockBuffer(); + pathBuffer.Append("kernel"); + AddPath(pathBuffer.Path(), subPath); + } + } + } else + AddPath(path, subPath); +} + + +status_t +DirectoryIterator::GetNext(KPath& path, struct stat& stat) +{ +next_directory: + while (fDirectory == NULL) { + delete fBasePath; + fBasePath = NULL; + + if (!fPaths.Pop(&fBasePath)) + return B_ENTRY_NOT_FOUND; + + fDirectory = opendir(fBasePath->Path()); + } + +next_entry: + struct dirent* dirent = readdir(fDirectory); + if (dirent == NULL) { + // get over to next directory on the stack + closedir(fDirectory); + fDirectory = NULL; + + goto next_directory; + } + + if (!strcmp(dirent->d_name, "..") || !strcmp(dirent->d_name, ".")) + goto next_entry; + + fCurrentName = dirent->d_name; + + path.SetTo(fBasePath->Path()); + path.Append(fCurrentName); + + if (::stat(path.Path(), &stat) != 0) + goto next_entry; + + if (S_ISDIR(stat.st_mode) && fRecursive) { + KPath *nextPath = new(nothrow) KPath(path); + if (!nextPath) + return B_NO_MEMORY; + if (fPaths.Push(nextPath) != B_OK) + return B_NO_MEMORY; + + goto next_entry; + } + + return B_OK; +} + + +void +DirectoryIterator::Unset() +{ + if (fDirectory != NULL) { + closedir(fDirectory); + fDirectory = NULL; + } + + delete fBasePath; + fBasePath = NULL; + + KPath *path; + while (fPaths.Pop(&path)) + delete path; +} + + +void +DirectoryIterator::AddPath(const char* basePath, const char* subPath) +{ + KPath *path = new(nothrow) KPath(basePath); + if (!path) + panic("out of memory"); + if (subPath != NULL) + path->Append(subPath); + + fPaths.Push(path); +} + + +// #pragma mark - + + +DirectoryWatcher::DirectoryWatcher() +{ +} + + +DirectoryWatcher::~DirectoryWatcher() +{ +} + + +void +DirectoryWatcher::EventOccured(NotificationService& service, + const KMessage* event) +{ + int32 opcode = event->GetInt32("opcode", -1); + dev_t device = event->GetInt32("device", -1); + ino_t directory = event->GetInt64("directory", -1); + const char *name = event->GetString("name", NULL); + + if (opcode == B_ENTRY_MOVED) { + // Determine wether it's a move within, out of, or into one + // of our watched directories. + ino_t from = event->GetInt64("from directory", -1); + ino_t to = event->GetInt64("to directory", -1); + if (sDirectoryNodeHash.Lookup(&from) == NULL) { + directory = to; + opcode = B_ENTRY_CREATED; + } else if (sDirectoryNodeHash.Lookup(&to) == NULL) { + directory = from; + opcode = B_ENTRY_REMOVED; + } else { + // Move within, don't do anything for now + // TODO: adjust driver priority if necessary + return; + } + } + + KPath path(B_PATH_NAME_LENGTH + 1); + if (path.InitCheck() != B_OK || vfs_entry_ref_to_path(device, directory, + name, path.LockBuffer(), path.BufferSize()) != B_OK) + return; + + path.UnlockBuffer(); + + dprintf("driver \"%s\" %s\n", path.Leaf(), + opcode == B_ENTRY_CREATED ? "added" : "removed"); + +#if 0 + switch (opcode) { + case B_ENTRY_CREATED: + devfs_driver_added(path.Path()); + break; + case B_ENTRY_REMOVED: + devfs_driver_removed(path.Path()); + break; + } +#endif +} + + +// #pragma mark - + + +static void +start_watching(const char *base, const char *sub) +{ + KPath path(base); + path.Append(sub); + + // TODO: create missing directories? + struct stat stat; + if (::stat(path.Path(), &stat) != 0) + return; + + add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, + sDirectoryWatcher); + + directory_node_entry *entry = new(std::nothrow) directory_node_entry; + if (entry != NULL) { + entry->node = stat.st_ino; + sDirectoryNodeHash.Insert(entry); + } +} + + +static struct driver_entry* +new_driver_entry(const char* path, dev_t device, ino_t node) +{ + driver_entry* entry = (driver_entry*)malloc(sizeof(driver_entry)); + if (entry == NULL) + return NULL; + + entry->path = strdup(path); + if (entry->path == NULL) { + free(entry); + return NULL; + } + + entry->device = device; + entry->node = node; + entry->busses = 0; + return entry; +} + + +/*! Iterates over the given list and tries to load all drivers in that list. + The list is emptied and freed during the traversal. +*/ +static status_t +try_drivers(DriverEntryList& list) +{ + while (true) { + driver_entry* entry = list.RemoveHead(); + if (entry == NULL) + break; + + image_id image = load_kernel_add_on(entry->path); + if (image >= 0) { + // check if it's an old-style driver + if (legacy_driver_add(entry->path) == B_OK) { + // we have a driver + dprintf("loaded driver %s\n", entry->path); + } + + unload_kernel_add_on(image); + } + + free(entry->path); + free(entry); + } + + return B_OK; +} + + +static status_t +probe_for_drivers(const char *type) +{ + TRACE(("probe_for_drivers(type = %s)\n", type)); + + if (gBootDevice < 0) + return B_OK; + + DriverEntryList drivers; + + // build list of potential drivers for that type + + DirectoryIterator iterator(NULL, type, false); + struct stat stat; + KPath path; + + while (iterator.GetNext(path, stat) == B_OK) { + if (S_ISDIR(stat.st_mode)) { + add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, + sDirectoryWatcher); + + directory_node_entry *entry + = new(std::nothrow) directory_node_entry; + if (entry != NULL) { + entry->node = stat.st_ino; + sDirectoryNodeHash.Insert(entry); + } + + // We need to make sure that drivers in ie. "audio/raw/" can + // be found as well - therefore, we must make sure that "audio" + // exists on /dev. + + size_t length = strlen("drivers/dev"); + if (strncmp(type, "drivers/dev", length)) + continue; + + path.SetTo(type); + path.Append(iterator.CurrentName()); + devfs_publish_directory(path.Path() + length + 1); + continue; + } + + driver_entry *entry = new_driver_entry(path.Path(), stat.st_dev, + stat.st_ino); + if (entry == NULL) + return B_NO_MEMORY; + + TRACE(("found potential driver: %s\n", path.Path())); + drivers.Add(entry); + } + + if (drivers.IsEmpty()) + return B_OK; + + // ToDo: do something with the remaining drivers... :) + try_drivers(drivers); + return B_OK; +} + + +// #pragma mark - LegacyDevice + + +LegacyDevice::LegacyDevice(legacy_driver* driver, const char* path, + device_hooks* hooks) + : + fDriver(driver) +{ + fDeviceModule = (device_module_info*)malloc(sizeof(device_module_info)); + if (fDeviceModule != NULL) + memset(fDeviceModule, 0, sizeof(device_module_info)); + + fDeviceData = this; + fPath = strdup(path); + + SetHooks(hooks); +} + + +LegacyDevice::~LegacyDevice() +{ + free(fDeviceModule); + free((char*)fPath); +} + + +status_t +LegacyDevice::InitCheck() const +{ + return fDeviceModule != NULL && fPath != NULL ? B_OK : B_NO_MEMORY; +} + + +status_t +LegacyDevice::InitDevice() +{ + MutexLocker _(sLock); + + if (fInitialized++ > 0) + return B_OK; + + if (fDriver != NULL && fDriver->devices_used == 0 + && (fDriver->image < 0 || fDriver->binary_updated)) { + status_t status = reload_driver(fDriver); + if (status < B_OK) + return status; + } + + if (fDriver != NULL) + fDriver->devices_used++; + + return B_OK; +} + + +void +LegacyDevice::UninitDevice() +{ + MutexLocker _(sLock); + + if (fInitialized-- > 1) + return; + + if (fDriver != NULL) + fDriver->devices_used--; +} + + +void +LegacyDevice::SetHooks(device_hooks* hooks) +{ + // TODO: setup compatibility layer! + fHooks = hooks; + + fDeviceModule->close = hooks->close; + fDeviceModule->free = hooks->free; + fDeviceModule->control = hooks->control; + fDeviceModule->read = hooks->read; + fDeviceModule->write = hooks->write; + + if (fDriver == NULL || fDriver->api_version >= 2) { + // According to Be newsletter, vol II, issue 36, + // version 2 added readv/writev, which we don't support, but also + // select/deselect. + fDeviceModule->select = (status_t (*)(void*, uint8, selectsync*))~0; + fDeviceModule->deselect = hooks->deselect; + } +} + + +status_t +LegacyDevice::Open(const char* path, int openMode, void** _cookie) +{ + return Hooks()->open(path, openMode, _cookie); +} + + +status_t +LegacyDevice::Select(void* cookie, uint8 event, selectsync* sync) +{ + return Hooks()->select(cookie, event, 0, sync); +} + + +// #pragma mark - kernel private API + + +extern "C" void +legacy_driver_add_preloaded(kernel_args* args) +{ + // NOTE: This function does not exit in case of error, since it + // needs to unload the images then. Also the return code of + // the path operations is kept separate from the add_driver() + // success, so that even if add_driver() fails for one driver, it + // is still tried for the other drivers. + // NOTE: The initialization success of the path objects is implicitely + // checked by the immediately following functions. + KPath basePath; + status_t pathStatus = find_directory(B_BEOS_ADDONS_DIRECTORY, + gBootDevice, false, basePath.LockBuffer(), basePath.BufferSize()); + if (pathStatus != B_OK) { + dprintf("devfs_add_preloaded_drivers: find_directory() failed: " + "%s\n", strerror(pathStatus)); + } + basePath.UnlockBuffer(); + if (pathStatus == B_OK) + pathStatus = basePath.Append("kernel"); + if (pathStatus != B_OK) { + dprintf("devfs_add_preloaded_drivers: constructing base driver " + "path failed: %s\n", strerror(pathStatus)); + } + + struct preloaded_image* image; + for (image = args->preloaded_images; image != NULL; image = image->next) { + if (image->is_module || image->id < 0) + continue; + + KPath imagePath(basePath); + if (pathStatus == B_OK) + pathStatus = imagePath.Append(image->name); + + // try to add the driver + status_t addStatus = pathStatus; + if (pathStatus == B_OK) + addStatus = add_driver(imagePath.Path(), image->id); + if (addStatus != B_OK) { + dprintf("devfs_add_preloaded_drivers: Failed to add \"%s\"\n", + image->name); + unload_kernel_add_on(image->id); + } + } +} + + +extern "C" status_t +legacy_driver_add(const char* path) +{ + return add_driver(path, -1); +} + + +extern "C" void +devfs_driver_added(const char *path) +{ + int32 priority = get_priority(path); + MutexLocker locker(sLock); + + legacy_driver *driver = (legacy_driver *)hash_lookup(sDriverHash, + get_leaf(path)); + + if (driver == NULL) { + // Add the driver to our list + path_entry *entry = new(std::nothrow) path_entry; + if (entry == NULL) + return; + + strlcpy(entry->path, path, sizeof(entry->path)); + sDriversToAdd.Add(entry); + } else { + // Update the driver if it is affected by the new entry + if (priority < driver->priority) + return; + + driver->binary_updated = true; + } + + atomic_add(&sDriverEvents, 1); +} + + +extern "C" void +devfs_driver_removed(const char* path) +{ + int32 priority = get_priority(path); + MutexLocker locker(sLock); + + legacy_driver* driver = (legacy_driver*)hash_lookup(sDriverHash, + get_leaf(path)); + if (driver == NULL || priority < driver->priority) + return; + + driver->binary_updated = true; + atomic_add(&sDriverEvents, 1); +} + + +extern "C" status_t +legacy_driver_publish(const char *path, device_hooks *hooks) +{ + // we don't have a driver, just publish the hooks + LegacyDevice* device = new(std::nothrow) LegacyDevice(NULL, path, hooks); + if (device == NULL) + return B_NO_MEMORY; + + status_t status = device->InitCheck(); + if (status == B_OK) + status = devfs_publish_device(path, device); + + if (status != B_OK) + delete device; + + return status; +} + + +extern "C" status_t +legacy_driver_rescan(const char* driverName) +{ + MutexLocker locker(sLock); + + legacy_driver* driver = (legacy_driver*)hash_lookup(sDriverHash, + driverName); + if (driver == NULL) + return B_ENTRY_NOT_FOUND; + + // Republish the driver's entries + return republish_driver(driver); +} + + +extern "C" status_t +legacy_driver_probe(const char* subPath) +{ + TRACE(("legacy_driver_probe(type = %s)\n", subPath)); + + char devicePath[64]; + snprintf(devicePath, sizeof(devicePath), "drivers/dev%s%s", + subPath[0] ? "/" : "", subPath); + + if (!sWatching && gBootDevice > 0) { + // We're probing the actual boot volume for the first time, + // let's watch its driver directories for changes + const directory_which whichPath[] = { + B_USER_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY + }; + KPath path; + + new(&sDirectoryWatcher) DirectoryWatcher; + + bool disableUserAddOns = get_safemode_boolean( + B_SAFEMODE_DISABLE_USER_ADD_ONS, false); + + for (uint32 i = 0; i < sizeof(whichPath) / sizeof(whichPath[0]); i++) { + if (i < 2 && disableUserAddOns) + continue; + + if (find_directory(whichPath[i], gBootDevice, true, + path.LockBuffer(), path.BufferSize()) == B_OK) { + path.UnlockBuffer(); + path.Append("kernel/drivers"); + + start_watching(path.Path(), "dev"); + start_watching(path.Path(), "bin"); + } + } + + sWatching = true; + } + + return probe_for_drivers(devicePath); +} + + +extern "C" status_t +legacy_driver_init(void) +{ + sDriverHash = hash_init(DRIVER_HASH_SIZE, offsetof(legacy_driver, next), + &driver_entry_compare, &driver_entry_hash); + if (sDriverHash == NULL) + return B_NO_MEMORY; + + mutex_init(&sLock, "legacy driver"); + + new(&sDriverWatcher) DriverWatcher; + new(&sDriversToAdd) DoublyLinkedList; + + register_kernel_daemon(&handle_driver_events, NULL, 10); + // once every second + + add_debugger_command("legacy_driver", &dump_driver, + "info about a legacy driver entry"); + + return B_OK; +} diff --git a/src/system/kernel/device_manager/legacy_drivers.h b/src/system/kernel/device_manager/legacy_drivers.h new file mode 100644 index 0000000000..a74f56c93c --- /dev/null +++ b/src/system/kernel/device_manager/legacy_drivers.h @@ -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 + + +#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 diff --git a/src/system/kernel/device_manager/probe.cpp b/src/system/kernel/device_manager/probe.cpp deleted file mode 100644 index 03af06a6a8..0000000000 --- a/src/system/kernel/device_manager/probe.cpp +++ /dev/null @@ -1,1479 +0,0 @@ -/* - * 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. - */ - -/* - Probing for consumers. - Here is all the core logic how consumers are found for one node. -*/ - - -#include "device_manager_private.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -//#define TRACE_PROBE -#ifdef TRACE_PROBE -# define TRACE(x) dprintf x -#else -# define TRACE(x) ; -#endif - - -struct path_entry { - struct list_link link; - char *path; - dev_t device; - ino_t node; - int32 busses; -}; - -struct module_entry { - struct list_link link; - char *name; - driver_module_info *driver; - float support; - bool no_connection; -}; - -struct directory_node_entry { - HashTableLink link; - ino_t node; -}; - -struct DirectoryNodeHashDefinition { - typedef ino_t *KeyType; - typedef directory_node_entry ValueType; - - size_t HashKey(ino_t *key) const - { return _Hash(*key); } - size_t Hash(directory_node_entry *entry) const - { return _Hash(entry->node); } - bool Compare(ino_t *key, directory_node_entry *entry) const - { return *key == entry->node; } - HashTableLink* GetLink(directory_node_entry *entry) const - { return &entry->link; } - - uint32 _Hash(ino_t node) const - { return (uint32)(node >> 32) + (uint32)node; } -}; - -typedef OpenHashTable DirectoryNodeHash; - -// list of driver registration directories -const char *pnp_registration_dirs[2] = { - COMMON_DRIVER_REGISTRATION, - SYSTEM_DRIVER_REGISTRATION -}; - - -class DirectoryIterator { - public: - DirectoryIterator(const char *path, const char *subPath = NULL, - bool recursive = false); - ~DirectoryIterator(); - - void SetTo(const char *path, const char *subPath = NULL, - bool recursive = false); - - status_t GetNext(KPath &path, struct stat &stat); - const char *CurrentName() const { return fCurrentName; } - - void Unset(); - void AddPath(const char *path, const char *subPath = NULL); - - private: - Stack fPaths; - bool fRecursive; - DIR *fDirectory; - KPath *fBasePath; - const char *fCurrentName; -}; - - -class DirectoryWatcher : public NotificationListener { - public: - DirectoryWatcher(); - virtual ~DirectoryWatcher(); - - virtual void EventOccured(NotificationService& service, - const KMessage* event); -}; - - -static DirectoryWatcher sDirectoryWatcher; -static DirectoryNodeHash sDirectoryNodeHash; -static bool sWatching; - - -DirectoryIterator::DirectoryIterator(const char *path, const char *subPath, - bool recursive) - : - fDirectory(NULL), - fBasePath(NULL), - fCurrentName(NULL) -{ - SetTo(path, subPath, recursive); -} - - -DirectoryIterator::~DirectoryIterator() -{ - Unset(); -} - - -void -DirectoryIterator::SetTo(const char *path, const char *subPath, bool recursive) -{ - Unset(); - fRecursive = recursive; - - if (path == NULL) { - // add default paths - const directory_which whichPath[] = { - B_USER_ADDONS_DIRECTORY, - B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY - }; - KPath pathBuffer; - - bool disableUserAddOns = get_safemode_boolean( - B_SAFEMODE_DISABLE_USER_ADD_ONS, false); - - for (uint32 i = 0; i < sizeof(whichPath) / sizeof(whichPath[0]); i++) { - if (i < 2 && disableUserAddOns) - continue; - - if (find_directory(whichPath[i], gBootDevice, true, - pathBuffer.LockBuffer(), pathBuffer.BufferSize()) == B_OK) { - pathBuffer.UnlockBuffer(); - pathBuffer.Append("kernel"); - AddPath(pathBuffer.Path(), subPath); - } - } - } else - AddPath(path, subPath); -} - - -status_t -DirectoryIterator::GetNext(KPath &path, struct stat &stat) -{ -next_directory: - while (fDirectory == NULL) { - delete fBasePath; - fBasePath = NULL; - - if (!fPaths.Pop(&fBasePath)) - return B_ENTRY_NOT_FOUND; - - fDirectory = opendir(fBasePath->Path()); - } - -next_entry: - struct dirent *dirent = readdir(fDirectory); - if (dirent == NULL) { - // get over to next directory on the stack - closedir(fDirectory); - fDirectory = NULL; - - goto next_directory; - } - - if (!strcmp(dirent->d_name, "..") || !strcmp(dirent->d_name, ".")) - goto next_entry; - - fCurrentName = dirent->d_name; - - path.SetTo(fBasePath->Path()); - path.Append(fCurrentName); - - if (::stat(path.Path(), &stat) != 0) - goto next_entry; - - if (S_ISDIR(stat.st_mode) && fRecursive) { - KPath *nextPath = new(nothrow) KPath(path); - if (!nextPath) - return B_NO_MEMORY; - if (fPaths.Push(nextPath) != B_OK) - return B_NO_MEMORY; - - goto next_entry; - } - - return B_OK; -} - - -void -DirectoryIterator::Unset() -{ - if (fDirectory != NULL) { - closedir(fDirectory); - fDirectory = NULL; - } - - delete fBasePath; - fBasePath = NULL; - - KPath *path; - while (fPaths.Pop(&path)) - delete path; -} - - -void -DirectoryIterator::AddPath(const char *basePath, const char *subPath) -{ - KPath *path = new(nothrow) KPath(basePath); - if (!path) - panic("out of memory"); - if (subPath != NULL) - path->Append(subPath); - - fPaths.Push(path); -} - - -// #pragma mark - - - -DirectoryWatcher::DirectoryWatcher() -{ -} - - -DirectoryWatcher::~DirectoryWatcher() -{ -} - - -void -DirectoryWatcher::EventOccured(NotificationService& service, - const KMessage* event) -{ - int32 opcode = event->GetInt32("opcode", -1); - dev_t device = event->GetInt32("device", -1); - ino_t directory = event->GetInt64("directory", -1); - const char *name = event->GetString("name", NULL); - - if (opcode == B_ENTRY_MOVED) { - // Determine wether it's a move within, out of, or into one - // of our watched directories. - ino_t from = event->GetInt64("from directory", -1); - ino_t to = event->GetInt64("to directory", -1); - if (sDirectoryNodeHash.Lookup(&from) == NULL) { - directory = to; - opcode = B_ENTRY_CREATED; - } else if (sDirectoryNodeHash.Lookup(&to) == NULL) { - directory = from; - opcode = B_ENTRY_REMOVED; - } else { - // Move within, don't do anything for now - // TODO: adjust driver priority if necessary - return; - } - } - - KPath path(B_PATH_NAME_LENGTH + 1); - if (path.InitCheck() != B_OK || vfs_entry_ref_to_path(device, directory, - name, path.LockBuffer(), path.BufferSize()) != B_OK) - return; - - path.UnlockBuffer(); - - dprintf("driver \"%s\" %s\n", path.Leaf(), - opcode == B_ENTRY_CREATED ? "added" : "removed"); - - switch (opcode) { - case B_ENTRY_CREATED: - devfs_driver_added(path.Path()); - break; - case B_ENTRY_REMOVED: - devfs_driver_removed(path.Path()); - break; - } -} - - -// #pragma mark - - - -static void -start_watching(const char *base, const char *sub) -{ - KPath path(base); - path.Append(sub); - - // TODO: create missing directories? - struct stat stat; - if (::stat(path.Path(), &stat) != 0) - return; - - add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, - sDirectoryWatcher); - - directory_node_entry *entry = new(std::nothrow) directory_node_entry; - if (entry != NULL) { - entry->node = stat.st_ino; - sDirectoryNodeHash.Insert(entry); - } -} - - -static struct path_entry * -new_path_entry(const char *path, dev_t device, ino_t node) -{ - path_entry *entry = (path_entry *)malloc(sizeof(path_entry)); - if (entry == NULL) - return NULL; - - entry->path = strdup(path); - if (entry->path == NULL) { - free(entry); - return NULL; - } - - entry->device = device; - entry->node = node; - entry->busses = 0; - return entry; -} - - -static struct path_entry * -copy_path_entry(path_entry *entry) -{ - path_entry *newEntry = (path_entry *)malloc(sizeof(struct path_entry)); - if (newEntry == NULL) - return NULL; - - *newEntry = *entry; - newEntry->path = strdup(entry->path); - if (newEntry->path == NULL) { - free(newEntry); - return NULL; - } - - return newEntry; -} - - -static void -free_module_entry(module_entry *entry) -{ - if (entry->name != NULL && entry->driver != NULL) - put_module(entry->name); - - free(entry->name); - free(entry); -} - - -static struct module_entry * -new_module_entry(const char *name, driver_module_info *driver) -{ - module_entry *entry = (module_entry *)malloc(sizeof(module_entry)); - if (entry == NULL) - return NULL; - - entry->name = strdup(name); - if (entry->name == NULL) { - free(entry); - return NULL; - } - - entry->driver = driver; - entry->support = -1.0f; - entry->no_connection = false; - return entry; -} - - -static module_entry * -find_module_entry(struct list *list, const char *name) -{ - module_entry *entry = NULL; - - while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) { - if (!strcmp(entry->name, name)) - return entry; - } - - return NULL; -} - - -static status_t -add_device_node(struct list *list, device_node_info *node) -{ - node_entry *entry = (node_entry *)malloc(sizeof(node_entry)); - if (entry == NULL) - return B_NO_MEMORY; - - entry->node = node; - - uint8 exploreLast = false; - pnp_get_attr_uint8(node, B_DRIVER_EXPLORE_LAST, &exploreLast, false); - - if (exploreLast) - list_add_link_to_tail(list, &entry->link); - else - list_add_link_to_head(list, &entry->link); - - return B_OK; -} - - -static status_t -get_next_device_node(struct list *list, uint32 *_cookie, - device_node_info **_node) -{ - node_entry *entry = (node_entry *)list_get_next_item(list, (void *)*_cookie); - if (entry == NULL) - return B_ENTRY_NOT_FOUND; - - *_node = entry->node; - *_cookie = (uint32)entry; - - return B_OK; -} - - -static void -remove_device_nodes(struct list *list) -{ - struct node_entry *entry; - - while ((entry = (node_entry *)list_remove_head_item(list)) != NULL) { - free(entry); - } -} - - -/*! Notify a consumer that a device he might handle is added - fileName - file name of consumer - (moved to end of file to avoid inlining) -*/ -static status_t -notify_probe_by_file(device_node_info *node, const char *fileName) -{ - char *bus; - size_t i, suffix_length; - const char *module_name; - const char device_suffix[] = "_device_v1"; - status_t res; - - TRACE(("notify_probe_by_file(%s)\n", fileName)); - - res = pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false); - if (res != B_OK) - return res; - - // check if it's a driver module - module_info **modules; - if ((res = load_module(fileName, &modules)) != B_OK) { - goto err; - } - - suffix_length = strlen(bus) + sizeof(device_suffix); - for (i = 0; modules[i]; i++) { - module_name = modules[i]->name; - TRACE(("notify_probe_by_file trying %s %s %s\n", module_name, bus, module_name + (strlen(module_name) - suffix_length + 1))); - if (strlen(module_name) > suffix_length - && !strncmp(module_name + (strlen(module_name) - suffix_length + 1), bus, strlen(bus)) - && !strncmp(module_name + (strlen(module_name) - - sizeof(device_suffix) + 1), device_suffix, - sizeof(device_suffix))) { - // found the module - res = dm_register_child_device(node, module_name, true); - break; - } - } - - unload_module(fileName); -err: - free(bus); - return res; -} - - -/*! Compose all possible names of Specific drivers; as there are - multiple names which only differ in length, the most specific - driver name gets stored in , whereas is a - list of lengths of individual driver names with index 0 - containing the length of the shortest and num_parts-1 the - length of the longest name; is a supplied buffer of - MAX_PATH+1 size -*/ -static status_t -compose_driver_names(device_node_info *node, const char *dir, - const char *filename_pattern, int num_parts, - char *path, char *buffer, size_t **res_term_array) -{ - size_t *term_array; - int id; - status_t res; - - term_array = (size_t *)malloc(num_parts * sizeof(size_t)); - if (term_array == NULL) - return B_NO_MEMORY; - - strlcpy(path, dir, B_PATH_NAME_LENGTH); - strlcat(path, "/", B_PATH_NAME_LENGTH); - - TRACE(("compose_driver_names(%s)\n", path)); - - benaphore_lock(&gNodeLock); - - res = pnp_expand_pattern(node, filename_pattern, path, buffer, - term_array, &id); - - benaphore_unlock(&gNodeLock); - - if (res != B_OK) - goto err; - - if (id != num_parts) { - panic("compose_driver_names: number of pattern parts in %s is inconsistent (%d!=%d)", - filename_pattern, num_parts, id); - } - - TRACE(("driver=%s, parts=%d\n", buffer, id)); - - *res_term_array = term_array; - return B_OK; - -err: - free(term_array); - return res; -} - - -/*! Notify all drivers under . If is true, notify all, - if false, stop once a drivers notification function returned B_OK - buffer - scratch buffer of size B_PATH_NAME_LENGTH + 1 ; destroyed on exit - return: B_NAME_NOT_FOUND, if tell_all is false and no driver returned B_OK -*/ -static status_t -try_drivers(device_node_info *node, char *directory, - bool tell_all, char *buffer) -{ - DIR *dir; - size_t dir_len; - struct dirent *entry; - int i; - - TRACE(("try_drivers(dir: %s)\n", directory)); - - // first try user drivers, then system drivers - for (i = 0; i < (disable_useraddons ? 1 : 2); ++i) { - strcpy(buffer, pnp_registration_dirs[i]); - strlcat(buffer, directory, B_PATH_NAME_LENGTH); - - TRACE(("cur_dir: %s\n", buffer)); - - dir_len = strlen(buffer); - - dir = opendir(buffer); - if (dir == NULL) { - //SHOW_ERROR(3, "Directory %s doesn't exists", buffer); - // directory doesn't exist - return tell_all ? B_OK : B_NAME_NOT_FOUND; - } - - while ((entry = readdir(dir)) != NULL) { - buffer[dir_len] = 0; - strlcat(buffer, "/", B_PATH_NAME_LENGTH); - strlcat(buffer, entry->d_name, B_PATH_NAME_LENGTH); - - // skip default directory entries - if (!strcmp( entry->d_name, ".") - || !strcmp( entry->d_name, "..")) - continue; - - if (notify_probe_by_file(node, buffer) == B_OK && !tell_all) { - // tell_all is false, return on first hit - closedir(dir); - return B_OK; - } - } - - closedir(dir); - } - - return tell_all ? B_OK : B_NAME_NOT_FOUND; -} - - -/*! Find normal child of node that are stored under ; first, we - look for a specific driver; if none could be found, find a generic - one path, buffer - used as scratch buffer (all of size B_PATH_NAME_LENGTH + 1) - return: B_NAME_NOT_FOUND if no consumer could be found -*/ -static status_t -find_normal_child(device_node_info *node, const char *dir, - const char *filename_pattern, int num_parts, - char *path, char *buffer, bool *found_normal_driver) -{ - status_t res; - size_t *term_array; - int i; - - // don't search for specific consumers if there is only a directory given - if (*filename_pattern) { - res = compose_driver_names(node, dir, filename_pattern, num_parts, - path, buffer, &term_array); - if (res != B_OK) - return res; - - // try to find specific driver, starting with most specific, i.e. - // the one with the longest name - for (i = num_parts - 1; i >= 0; --i) { - int j; - - //TRACE(("%d: %lu\n", i, term_array[i])); - path[term_array[i]] = 0; - - // first, check for user driver, then system driver - for (j = 0; j < (disable_useraddons ? 1 : 2); ++j) { - struct stat dummy; - - strcpy(buffer, pnp_registration_dirs[j]); - strlcat(buffer, path, B_PATH_NAME_LENGTH); - - // do a stat to avoid error message if Specific Driver - // isn't provided - if (lstat(buffer, &dummy) == 0) { - res = notify_probe_by_file(node, buffer); - if (res == B_OK) - // got him! - break; - } else { - TRACE(("Specific driver %s doesn't exist\n", buffer )); - } - } - } - - free(term_array); - - if (i >= 0) { - // found specific consumer - *found_normal_driver = true; - return B_OK; - } - } - - // no specific consumer - go through generic driver - strlcpy(path, dir, B_PATH_NAME_LENGTH); - strlcat(path, GENERIC_SUBDIR, B_PATH_NAME_LENGTH); - - if (try_drivers(node, path, false, buffer) != B_OK) { - *found_normal_driver = false; - return B_NAME_NOT_FOUND; - } - - *found_normal_driver = true; - return B_OK; -} - - -/*! Pre-process dynamic child name pattern. - split into directory and pattern and count split positions; - further, remove quotes from directory - pattern - pattern of consumer name - buffer - buffer to store results in - (returned strings all point to !) - filename_pattern - pattern of file name - *num_parts - number of split positions -*/ -static status_t -preprocess_child_names(const char *pattern, char *buffer, - char **filename_pattern, int *const num_parts) -{ - char *str, *dest; - bool parts_began; - - // make a copy of pattern as we will strip escapes from directory part - strlcpy(buffer, pattern, B_PATH_NAME_LENGTH); - - // find directory part and count splitpoints - parts_began = false; - *num_parts = 1; - - for (str = buffer; *str; ++str) { - switch (*str) { - case '\\': - // honour escaped characters, taking care of trailing escape - if (str[1]) - ++str; - break; - - case '|': - ++*num_parts; - parts_began = true; - break; - - case '%': - ++str; - - // find end of attribute name, taking care of escape sequences - for (; *str != 0; ++str) { - if (*str == '\\') { - if (str[1] != 0) - ++str; - } else if (*str == '%') - break; - } - - if (*str == 0) { - dprintf("missing matching '%%' in consumer pattern %s\n", pattern); - return B_BAD_VALUE; - } - break; - } - } - - *filename_pattern = buffer; - - // remove escape sequences from directory - for (str = buffer, dest = buffer; *str; ++str) { - if (str[0] == '\\' && str[1] != 0) - ++str; - - *dest++ = *str; - } - - *dest = '\0'; - - TRACE(("filename_pattern = %s, num_parts = %d\n", - *filename_pattern, *num_parts)); - - return B_OK; -} - - -/*! Find consumers for one given pattern - has_normal_drivers - in: true - don't search for specific driver - out: true - specific driver was found -*/ -static status_t -register_dynamic_child_device(device_node_info *node, const char *bus, - const char *pattern, bool *has_normal_driver) -{ - status_t status; - char *buffers; - char *filename_pattern; - int num_parts; - - TRACE(("register_dynamic_child_device(bus = %s, pattern = %s, has_normal_driver = %d)\n", - bus, pattern, *has_normal_driver)); - - if (pattern == NULL) - return B_OK; - - // we need three buffers - allocate them at once for simplicity - buffers = (char *)malloc(3 * (B_PATH_NAME_LENGTH + 1)); - if (buffers == NULL) - return B_NO_MEMORY; - - status = preprocess_child_names(pattern, buffers + 2 * (B_PATH_NAME_LENGTH + 1), - &filename_pattern, &num_parts); - if (status < B_OK) - goto err; - - if (!*has_normal_driver) { - // find specific/generic consumer - status = find_normal_child(node, bus, filename_pattern, num_parts, - buffers, buffers + B_PATH_NAME_LENGTH + 1, has_normal_driver); - if (status != B_OK && status != B_NAME_NOT_FOUND) - // only abort if there was a "real" problem; - // if there is no specific/generic consumer, we don't bother - // (having no driver is not funny but happens) - goto err; - } - -#if 0 - // tell universal drivers - strlcpy(buffers, bus, B_PATH_NAME_LENGTH); - strlcat(buffers, UNIVERSAL_SUBDIR, B_PATH_NAME_LENGTH); - - status = try_drivers(node, buffers, true, buffers + B_PATH_NAME_LENGTH + 1); - if (status != B_OK && status != B_NAME_NOT_FOUND) - // again, only abort on real problems - goto err; -#endif - - free(buffers); - - TRACE(("done\n")); - return B_OK; - -err: - free(buffers); - return status; -} - - -static path_entry * -find_node_ref_in_list(struct list *list, dev_t device, ino_t node) -{ - path_entry *entry = NULL; - - while ((entry = (path_entry *)list_get_next_item(list, entry)) != NULL) { - if (entry->device == device - && entry->node == node) - return entry; - } - - return NULL; -} - - -/*! Iterates over the given list and tries to load all drivers and modules - in that list. - The list is emptied and freed during the traversal. - - ToDo: Old style drivers will be initialized as well, new style driver - handling is not yet done. -*/ -static status_t -try_drivers(struct list &list, bool tryBusDrivers) -{ - path_entry *entry; - while ((entry = (path_entry *)list_remove_head_item(&list)) != NULL) { - if (!tryBusDrivers && entry->busses) { - free(entry->path); - free(entry); - continue; - } - - image_id image = load_kernel_add_on(entry->path); - if (image >= 0) { - // check if it's a driver module - module_info **modules; - if (load_module(entry->path, &modules) == B_OK) { - // we have a module - dprintf("loaded module %s\n", entry->path); - } else { - // it can still be a standard old-style driver - if (devfs_add_driver(entry->path) == B_OK) { - // we have a driver - dprintf("loaded driver %s\n", entry->path); - } - } - - unload_kernel_add_on(image); - } - - free(entry->path); - free(entry); - } - - return B_OK; -} - - -static module_entry * -remove_best_entry(struct list *list) -{ - module_entry *bestEntry = NULL; - module_entry *entry = NULL; - - while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) { - if (entry->no_connection || entry->driver == NULL - || entry->driver->register_device == NULL - || entry->support <= 0.0) - continue; - - if (bestEntry == NULL || bestEntry->support < entry->support) - bestEntry = entry; - } - - if (bestEntry) { - list_remove_item(list, bestEntry); - return bestEntry; - } - - return NULL; -} - - -static void -register_supporting_child_devices(device_node_info *node, struct list *list) -{ - // See if this node has a connection to offer - char *hasConnection = NULL; - // this is a bit ugly as we don't access the string - // but just test it against NULL - if (pnp_get_attr_string(node, PNP_DRIVER_CONNECTION, &hasConnection, false) == B_OK) - free(hasConnection); - dprintf("has connection? %s\n", hasConnection ? "yes" : "no"); - - // first ask each module for level of support - - module_entry *bestEntry = NULL; - module_entry *entry = NULL; - while ((entry = (module_entry *)list_get_next_item(list, entry)) != NULL) { - if (entry->driver == NULL) { - if (get_module(entry->name, (module_info **)&entry->driver) != B_OK) - continue; - } - - entry->support = entry->driver->supports_device(node, &entry->no_connection); - dprintf("module: %s, support: %f\n", entry->name, entry->support); - - if (!hasConnection) - entry->no_connection = true; - } - - // register best module with a connection - - while ((entry = remove_best_entry(list)) != NULL) { - status_t status = entry->driver->register_device(node); - dprintf("tried best module: %s: %s\n", entry->name, strerror(status)); - free_module_entry(entry); - - if (status == B_OK) - break; - } - - // register all modules that don't need a connection - // and empty the list - - while ((entry = (module_entry *)list_remove_head_item(list)) != NULL) { - if (entry->no_connection && entry->driver != NULL - && entry->driver->register_device != NULL - && entry->support > 0.0) { - dprintf("register rest: %s\n", entry->name); - entry->driver->register_device(node); - } - - dprintf("free %s\n", entry->name); - free_module_entry(entry); - } -} - - -static bool -is_driver_module(const char *name, int32 length) -{ - if (length == -1) - length = strlen(name); - - return !strcmp(name + length - 9, "device_v1"); -} - - -static status_t -get_loaded_modules(struct list *modules, const char *bus, const char *device) -{ - TRACE(("get_loaded_modules(bus = %s, device = %s)\n", bus, device)); - - bool listWasEmpty = list_is_empty(modules); - - char name[B_FILE_NAME_LENGTH]; - size_t size = sizeof(name); - uint32 cookie = 0; - while (get_next_loaded_module_name(&cookie, name, &size) == B_OK) { - int32 length = size; - size = sizeof(name); - - if (!is_driver_module(name, length)) - continue; - - TRACE((" \"%s\" is driver module!\n", name)); - - driver_module_info *info; - if (get_module(name, (module_info **)&info) == B_OK) { - if (info->get_supported_paths == NULL) { - put_module(name); - continue; - } - - const char **busses, **devices; - info->get_supported_paths(&busses, &devices); - - bool support = bus == NULL; - - // search for the bus - - if (bus != NULL && busses != NULL) { - for (int32 i = 0; busses[i]; i++) { - if (!strcmp(bus, busses[i])) { - dprintf("\tfound %s!!\n", busses[i]); - support = true; - break; - } - } - } - - if (support) { - // search for the device - - support = device == NULL; - - if (device != NULL && devices != NULL) { - for (int32 i = 0; devices[i]; i++) { - if (!strncmp(device, devices[i], strlen(device))) { - dprintf("\tfound %s!!\n", devices[i]); - support = true; - break; - } - } - } - } - - if (support && !listWasEmpty) { - // make sure we don't add the same module twice - if (find_module_entry(modules, name) != NULL) - support = false; - } - - if (support) { - module_entry *entry = new_module_entry(name, info); - if (entry == NULL) { - put_module(name); - return B_NO_MEMORY; - } - - dprintf("\tadd module %s to list\n", name); - list_add_item(modules, entry); - continue; - } - - put_module(name); - } - } - - return B_OK; -} - - -static status_t -get_nodes_for_device_type(device_node_info *node, struct list *list, - const char *type) -{ - bool matches = false; - - // see if there is a B_DRIVER_DEVICE_TYPE that matches the query - - char *deviceType = NULL; - if (pnp_get_attr_string(node, B_DRIVER_DEVICE_TYPE, &deviceType, false) == B_OK) { - if (!strncmp(deviceType, type, strlen(type))) - matches = true; - - free(deviceType); - } - - if (!matches) { - // we also accept any dump busses - uint8 onDemand = false; - pnp_get_attr_uint8(node, B_DRIVER_FIND_DEVICES_ON_DEMAND, &onDemand, - false); - - if (onDemand) - matches = true; - } - - if (matches && list_get_first_item(&node->children) == NULL) { -#ifdef TRACE_PROBE - dprintf("** NODE MATCHES TYPE %s\n", type); - dm_dump_node(node, 0); -#endif - return add_device_node(list, node); - } - - // search child nodes, then - device_node_info *child = NULL; - while (dm_get_next_child_node(node, &child, NULL) == B_OK) { - status_t status = get_nodes_for_device_type(child, list, type); - if (status != B_OK) { - dm_put_node(child); - return status; - } - } - - return B_OK; -} - - -// #pragma mark - -// device manager private API - - -/*! Register the device of a child for the \a node that might accept it. - childName - module name of child/consumer -*/ -status_t -dm_register_child_device(device_node_info *node, const char *childName, - bool checkSupport) -{ - driver_module_info *child; - status_t status; - - TRACE(("dm_register_child_device(node = %p, child = %s)\n", node, childName)); - - status = get_module(childName, (module_info **)&child); - if (status < B_OK) { - dprintf("Cannot load driver module %s (%s)\n", childName, strerror(status)); - return status; - } - - status = B_ERROR; - bool hasConnection; - if (checkSupport) { - if (child->supports_device == NULL) { - dprintf("Driver %s has no support_device() hook\n", childName); - goto err; - } - if (child->supports_device(node, &hasConnection) <= 0.0) { - TRACE(("Driver %s doesn't support the device\n", childName)); - goto err; - } - } - - if (child->register_device != NULL) { - status = child->register_device(node); - if (status != B_OK) { - TRACE(("dm_register_child_device(): Driver %s returned: %s\n", - childName, strerror(status))); - } - } else { - dprintf("Driver %s has no register_device() hook\n", childName); - status = B_ERROR; - } - -err: - put_module(childName); - return status; -} - - -/*! Find and notify dynamic consumers that device was added - errors returned by consumers aren't reported, only problems - like malformed consumer patterns -*/ -status_t -dm_register_dynamic_child_devices(device_node_info *node) -{ - char *buffer; - char *bus; - status_t status = B_OK; - int32 i, found = 0; - - TRACE(("dm_register_dynamic_child_devices(node = %p)\n", node)); - - if (pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false) != B_OK) - return B_OK; - - TRACE((" Search bus: \"%s\"\n", bus)); - - if (gBootDevice < 0) { - TRACE((" Scanning built-in modules only\n")); - // there is no boot device yet, we have to scan the already - // loaded and built-in modules - struct list modules; - list_init(&modules); - - status = get_loaded_modules(&modules, bus, NULL); - if (status != B_OK) - return status; - - register_supporting_child_devices(node, &modules); - return B_OK; - } else { - buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1); - if (buffer == NULL) { - status = B_NO_MEMORY; - goto err; - } - - // first, append nothing, then "/0", "/1" etc. - for (i = -1; ; ++i) { - bool noSpecificDriver = false; - char *consumer; - - strcpy(buffer, B_DRIVER_MAPPING); - if (i >= 0) - sprintf(buffer + strlen( buffer ), "/%ld", i); - - // if no more dynamic consumers, cancel loop silently - if (pnp_get_attr_string(node, buffer, &consumer, false) != B_OK) { - // starting with .../0 is OK, so ignore error if i = -1 - if (i == -1) - continue; - else - break; - } - - TRACE((" Consumer pattern %ld: %s\n", i, consumer)); - status = register_dynamic_child_device(node, bus, consumer, &noSpecificDriver); - - free(consumer); - found++; - - if (status != B_OK) { - // this is only reached if a serious error occured, - // see register_dynamic_child_device() - break; - } - } - } - - if (found == 0) { - // no requirement for a special mapping, so we're just scanning the bus directory - bool noSpecificDriver = false; - status = register_dynamic_child_device(node, bus, NULL, &noSpecificDriver); - } - - // supposed to go through - free(buffer); -err: - free(bus); - return status; -} - - -/*! Register all fixed child devices of of the given \a node; in contrast - to dynamic child devices, errors reported by fixed child devices are - not ignored but returned, and regarded critical. -*/ -status_t -dm_register_fixed_child_devices(device_node_info *node) -{ - TRACE(("dm_register_fixed_child_devices(node = %p)\n", node)); - - char *buffer = (char *)malloc(B_PATH_NAME_LENGTH + 1); - if (buffer == NULL) - return B_NO_MEMORY; - - // first, append nothing, then "/0", "/1" etc. - for (int32 i = -1; ; ++i) { - char *childName; - - strcpy(buffer, B_DRIVER_FIXED_CHILD); - if (i >= 0) - sprintf(buffer + strlen(buffer), "/%ld", i); - - // if no more fixed consumers, cancel loop silently - if (pnp_get_attr_string(node, buffer, &childName, false) != B_OK) - break; - - TRACE(("Consumer %ld: %s\n", i, childName)); - - if (dm_register_child_device(node, childName, false) != B_OK) { - dprintf("Cannot register fixed child device %s\n", childName); - - // report error if fixed consumers couldn't be loaded - // as they are obviously crucial (else they wouldn't be fixed) - - // ToDo: what about the devices we already registered up to this point? - free(childName); - free(buffer); - return B_NAME_NOT_FOUND; - } - - free(childName); - } - - free(buffer); - return B_OK; -} - - -static status_t -probe_for_driver_modules(const char *type) -{ - TRACE(("probe_for_driver_modules(type = %s)\n", type)); - - // search a node with an open connection of the specified type - // or notify bus managers to get one - - status_t status = B_OK; - struct list drivers; - list_init(&drivers); - - if (gBootDevice < 0) { - struct list nodes; - list_init(&nodes); - - get_nodes_for_device_type(gRootNode, &nodes, type); - - device_node_info *node; - uint32 cookie = 0; - while (get_next_device_node(&nodes, &cookie, &node) == B_OK) { - char *bus; - if (pnp_get_attr_string(node, B_DRIVER_BUS, &bus, false) == B_OK) { - struct list drivers; - list_init(&drivers); - get_loaded_modules(&drivers, bus, type); - - register_supporting_child_devices(node, &drivers); - - free(bus); - } - } - - remove_device_nodes(&nodes); - return B_OK; - } - - // build list of potential drivers for that type - - DirectoryIterator iterator(NULL, type, false); - struct stat stat; - KPath path; - - while (iterator.GetNext(path, stat) == B_OK) { - if (S_ISDIR(stat.st_mode)) { - add_node_listener(stat.st_dev, stat.st_ino, B_WATCH_DIRECTORY, - sDirectoryWatcher); - - directory_node_entry *entry - = new(std::nothrow) directory_node_entry; - if (entry != NULL) { - entry->node = stat.st_ino; - sDirectoryNodeHash.Insert(entry); - } - - // We need to make sure that drivers in ie. "audio/raw/" can - // be found as well - therefore, we must make sure that "audio" - // exists on /dev. - - size_t length = strlen("drivers/dev"); - if (strncmp(type, "drivers/dev", length)) - continue; - - path.SetTo(type); - path.Append(iterator.CurrentName()); - devfs_publish_directory(path.Path() + length + 1); - continue; - } - - path_entry *entry = new_path_entry(path.Path(), stat.st_dev, stat.st_ino); - if (entry == NULL) - return B_NO_MEMORY; - - TRACE(("found potential driver: %s\n", path.Path())); - list_add_item(&drivers, entry); - } - - if (list_is_empty(&drivers)) - return B_OK; - - // Iterate through bus managers to shrink the list (let them publish - // their own devices) - - iterator.SetTo(NULL, "drivers/bus", false); - - while (iterator.GetNext(path, stat) == B_OK) { - DirectoryIterator busIterator(path.Path(), NULL, true); - - struct list driversForBus; - list_init(&driversForBus); - - dprintf("bus: %s\n", path.Leaf()); - - while (busIterator.GetNext(path, stat) == B_OK) { - path_entry *entry = find_node_ref_in_list(&drivers, stat.st_dev, - stat.st_ino); - if (entry == NULL) - continue; - - entry->busses++; - // mark this entry as being used by a bus - - // ToDo: we don't need to remember drivers when there is no bus for them - // (ie. no need to store ISA drivers when there is no ISA bus in the system) - - entry = copy_path_entry(entry); - if (entry == NULL) - continue; - - list_add_item(&driversForBus, entry); - dprintf("found driver for bus \"%s\": \"%s\"\n", path.Path(), entry->path); - } - - // ToDo: do something with the bus drivers... :) - // ToDo: ask bus manager for driver (via mapping) - // ToDo: find all nodes where this driver could be attached to - try_drivers(driversForBus, true); - } - - // ToDo: do something with the remaining drivers... :) - try_drivers(drivers, false); - return B_OK; -} - - -status_t -probe_for_device_type(const char *type) -{ - TRACE(("probe_for_device_type(type = %s)\n", type)); - - char deviceType[64]; - snprintf(deviceType, sizeof(deviceType), "drivers/dev%s%s", - type[0] ? "/" : "", type); - - if (!sWatching && gBootDevice > 0) { - // We're probing the actual boot volume for the first time, - // let's watch its driver directories for changes - const directory_which whichPath[] = { - B_USER_ADDONS_DIRECTORY, - B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY - }; - KPath path; - - new(&sDirectoryWatcher) DirectoryWatcher; - - bool disableUserAddOns = get_safemode_boolean( - B_SAFEMODE_DISABLE_USER_ADD_ONS, false); - - for (uint32 i = 0; i < sizeof(whichPath) / sizeof(whichPath[0]); i++) { - if (i < 2 && disableUserAddOns) - continue; - - if (find_directory(whichPath[i], gBootDevice, true, - path.LockBuffer(), path.BufferSize()) == B_OK) { - path.UnlockBuffer(); - path.Append("kernel/drivers"); - - start_watching(path.Path(), "dev"); - start_watching(path.Path(), "bin"); - } - } - - sWatching = true; - } - - return probe_for_driver_modules(deviceType); -} diff --git a/src/system/kernel/fs/Jamfile b/src/system/kernel/fs/Jamfile index ae16b005b1..138aad6dbf 100644 --- a/src/system/kernel/fs/Jamfile +++ b/src/system/kernel/fs/Jamfile @@ -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 diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index 935cf631bd..8bf022b309 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.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; diff --git a/src/system/kernel/module.cpp b/src/system/kernel/module.cpp index c9dcf606df..596ae0dbb1 100644 --- a/src/system/kernel/module.cpp +++ b/src/system/kernel/module.cpp @@ -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) {