Remove ISA floppy driver code

We removed config_manager which the code is based on, and
the driver was not working before that.

Perhaps it is time to pour one out for the floppy driver?

Change-Id: I306f7bda08ad8fe3f64b55cb147a1e2dea6ddfef
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5221
Reviewed-by: Fredrik Holmqvist <fredrik.holmqvist@gmail.com>
This commit is contained in:
Fredrik Holmqvist 2022-07-15 21:14:41 +02:00
parent 75c76bec99
commit 9ee255851d
8 changed files with 0 additions and 1827 deletions

View File

@ -1,6 +1,5 @@
SubDir HAIKU_TOP src add-ons kernel drivers disk ;
SubInclude HAIKU_TOP src add-ons kernel drivers disk floppy ;
SubInclude HAIKU_TOP src add-ons kernel drivers disk mmc ;
SubInclude HAIKU_TOP src add-ons kernel drivers disk norflash ;
SubInclude HAIKU_TOP src add-ons kernel drivers disk nvme ;

View File

@ -1,3 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel drivers disk floppy ;
SubInclude HAIKU_TOP src add-ons kernel drivers disk floppy pc_floppy ;

View File

@ -1,11 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel drivers disk floppy pc_floppy ;
UsePrivateHeaders drivers ;
UsePrivateKernelHeaders ;
KernelAddon pc_floppy :
floppy.c
floppy_ctrl.c
device_icons.c
;

View File

@ -1,93 +0,0 @@
/*
* Copyright 2003-2008, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
const char floppy_icon[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0x0e,
0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x00, 0x0f,
0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x04, 0x00, 0x00,
0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x04, 0x00, 0x2d, 0x2e,
0x2d, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x04, 0x00, 0x3f, 0x3f, 0x2d,
0x2e, 0x2d, 0xd2, 0x00, 0x00, 0x0e, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x04, 0x00, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0xd2, 0xd2, 0xd2, 0xd2, 0x00, 0x00, 0x0e, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x04, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0x3f, 0x3f, 0xd2, 0xd2, 0xd2, 0xd2, 0x00, 0x00, 0x0e, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x04, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xd2, 0xd2, 0x00, 0x17, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0e, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x0a, 0x0b, 0x17, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x17, 0x0b, 0x0a, 0x0b, 0x00, 0x0f, 0x0f, 0x0e, 0xff,
0xff, 0xff, 0xff, 0x00, 0x0a, 0x0b, 0x0a, 0x0b, 0x0b, 0x0a, 0x18, 0x17, 0x00, 0x00, 0x3f, 0x3f,
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x17, 0x0b, 0x0a, 0x0b, 0x04, 0x00, 0x0f, 0x0f, 0x0f, 0xff,
0xff, 0xff, 0x00, 0x0a, 0x0b, 0x0a, 0x0b, 0x0b, 0x0a, 0x0b, 0x0b, 0x0a, 0x18, 0x17, 0x00, 0x00,
0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x17, 0x0b, 0x0a, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff,
0xff, 0x00, 0x0a, 0x0b, 0x0a, 0x0b, 0x15, 0x00, 0x00, 0x0b, 0x0b, 0x0a, 0x0b, 0x0a, 0x18, 0x17,
0x00, 0x00, 0x3f, 0x00, 0x17, 0x0b, 0x0a, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff,
0x00, 0x0a, 0x0b, 0x0a, 0x0b, 0x15, 0x00, 0x18, 0x17, 0x00, 0x00, 0x0b, 0x0a, 0x0b, 0x0b, 0x0a,
0x18, 0x17, 0x00, 0x17, 0x0b, 0x0b, 0x0a, 0x04, 0x05, 0x00, 0x0f, 0x0e, 0xff, 0xff, 0xff, 0xff,
0x00, 0x3f, 0x3f, 0x0a, 0x15, 0x00, 0x18, 0x17, 0x04, 0x0b, 0x17, 0x00, 0x00, 0x0b, 0x0b, 0x0a,
0x0b, 0x0b, 0x17, 0x0b, 0x0a, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x15, 0x15, 0x3f, 0x00, 0x17, 0x17, 0x05, 0x00, 0x04, 0x17, 0x18, 0x17, 0x00, 0x00, 0x0b,
0x0a, 0x0b, 0x0a, 0x0b, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x15, 0x00, 0x3f, 0x3f, 0x00, 0x04, 0x17, 0x18, 0x17, 0x17, 0x18, 0x17, 0x00,
0x0b, 0x0a, 0x0b, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x15, 0x15, 0x3f, 0x3f, 0x17, 0x17, 0x18, 0x17, 0x17, 0x00, 0x18,
0x0a, 0x0b, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x15, 0x15, 0x3f, 0x3f, 0x17, 0x17, 0x00, 0x18, 0x0a,
0x0b, 0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x15, 0x15, 0x3f, 0x00, 0x17, 0x0b, 0x0a,
0x0b, 0x04, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x15, 0x00, 0x3f, 0x3f, 0x0a,
0x04, 0x05, 0x00, 0x0f, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x15, 0x15, 0x04,
0x05, 0x00, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x04,
0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const char floppy_mini_icon[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0e, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x2d, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x3f, 0x2d, 0x2e, 0x2d, 0x00, 0x00, 0x0e, 0x0f, 0x0f, 0xff,
0xff, 0xff, 0x00, 0x0a, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0xd2, 0xd2, 0xd2, 0x00, 0x00, 0x0e, 0x0f,
0xff, 0x00, 0x0a, 0x0b, 0x0a, 0x00, 0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x0a, 0x00, 0x0f, 0x0f,
0x00, 0x0b, 0x0a, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x04, 0x00, 0x0f, 0x0f,
0x00, 0x3f, 0x00, 0x17, 0x17, 0x00, 0x00, 0x0b, 0x0b, 0x00, 0x0a, 0x04, 0x00, 0x0f, 0x0f, 0xff,
0x00, 0x15, 0x00, 0x3f, 0x3f, 0x17, 0x17, 0x00, 0x0b, 0x0b, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff,
0xff, 0x00, 0x00, 0x15, 0x15, 0x3f, 0x3f, 0x00, 0x0a, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x15, 0x00, 0x0a, 0x05, 0x00, 0x0f, 0x0e, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x04, 0x00, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

View File

@ -1,570 +0,0 @@
/*
* Copyright 2003-2008, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
/*
* inspired by the NewOS floppy driver
* http://www.newos.org/cgi-bin/fileDownLoad.cgi?FSPC=//depot/newos/kernel/addons/dev/arch/i386/floppy/floppy.c&REV=6
* related docs:
* - datasheets
* http://floppyutil.sourceforge.net/floppy.html
* http://www.openppc.org/datasheets/NatSemi_PC87308VUL_full.pdf
* http://www.smsc.com/main/datasheets/37c665gt.pdf
* http://www.smsc.com/main/datasheets/47b27x.pdf
* - sources
* http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/isa/fd.c
* http://fxr.watson.org/fxr/source/sys/fdcio.h?v=RELENG50
* http://fxr.watson.org/fxr/source/isa/fd.c?v=RELENG50
* http://lxr.linux.no/source/drivers/block/floppy.c
*/
/*
* the stupid FDC engine is able to use several drives at a time, but *only* for some commands,
* others need exclusive access, as they need the drive to be selected.
* we just serialize the whole thing to simplify.
*/
#include <Drivers.h>
#include <ISA.h>
#include <PCI.h>
#include <config_manager.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "floppy.h"
/* compile time configuration */
/* enables support for more than one drive */
#define NEW_DEV_LAYOUT
/* don't symlink raw -> 0/raw */
#define NO_SYMLINK_OLD
/* publish the first drive as floppy/raw */
#define FIRST_ONE_NO_NUMBER
/* default values... for 3"5 HD, but we support DD too now */
#define SECTORS_PER_TRACK 18
#define NUM_HEADS 2
#define SECTORS_PER_CYLINDER (SECTORS_PER_TRACK * NUM_HEADS)
#define SECTOR_SIZE 512
#define TRACK_SIZE (SECTOR_SIZE * SECTORS_PER_CYLINDER)
#define NUM_TRACKS 80
#define DISK_SIZE (TRACK_SIZE * NUM_TRACKS)
extern const char floppy_icon[];
extern const char floppy_mini_icon[];
#define OLD_DEV_FORMAT "disk/floppy/raw"
#ifndef NEW_DEV_LAYOUT
# define MAX_FLOPPIES 1
# define DEV_FORMAT OLD_DEV_FORMAT
#else
# define MAX_FLOPPIES 4
# define DEV_FORMAT "disk/floppy/%d/raw"
#endif
static char floppy_dev_name[MAX_FLOPPIES][B_OS_NAME_LENGTH];
static const char *dev_names[MAX_FLOPPIES+1];
extern device_hooks floppy_hooks;
int32 api_version = B_CUR_DRIVER_API_VERSION;
isa_module_info *isa;
config_manager_for_driver_module_info *config_man;
struct floppy floppies[MAX_FLOPPIES];
/* by order of check */
/* from fd.c from fBSD */
const floppy_geometry supported_geometries[] = {
/* { gap, nsecs, data_rate, fmtgap, sd2off, {secsz, s/trk, ntraks, nheads, type, rmable, ro, wonce}, flags, name }, */
{ 0x1b, 2880, FDC_500KBPS, 0x6c, 0, { 512, 18, 80, 2, B_DISK, true, true, false}, FL_MFM, "1.44M" },
/* { 0x20, 5760, FDC_1MBPS, 0x4c, 1, { 512, 36, 80, 2, B_DISK, true, true, false}, FL_MFM|FL_PERP, "2.88M" }, */
{ 0x20, 1440, FDC_250KBPS, 0x50, 0, { 512, 9, 80, 2, B_DISK, true, true, false}, FL_MFM, "720K" },
{ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, true, false, false}, 0, NULL }
};
typedef struct floppy_cookie {
struct floppy *flp;
} floppy_cookie;
static void motor_off_daemon(void *t, int tim);
status_t
init_hardware(void)
{
TRACE("init_hardware()\n");
/* assume there is always one */
return B_OK;
}
status_t
init_driver(void)
{
status_t err;
unsigned int i, j;
int current;
uint64 cmcookie = 0;
struct device_info info;
TRACE("init_driver()\n");
if ((err = get_module(B_ISA_MODULE_NAME, (module_info **)&isa)) < B_OK) {
dprintf(FLO "no isa module!\n");
return err;
}
if ((err = get_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME, (module_info **)&config_man)) < B_OK) {
dprintf(FLO "no config_manager module!\n");
put_module(B_ISA_MODULE_NAME);
return err;
}
for (i = 0; i < MAX_FLOPPIES; i++)
memset(&(floppies[i]), 0, sizeof(floppy_t));
current = 0;
register_kernel_daemon(motor_off_daemon, floppies, 5);
while (config_man->get_next_device_info(B_ISA_BUS, &cmcookie, &info, sizeof(struct device_info)) == B_OK) {
struct device_configuration *conf;
struct floppy *master;
struct floppy *last = NULL;
int flops;
if ((info.config_status != B_OK) ||
((info.flags & B_DEVICE_INFO_ENABLED) == 0) ||
((info.flags & B_DEVICE_INFO_CONFIGURED) == 0) ||
(info.devtype.base != PCI_mass_storage) ||
(info.devtype.subtype != PCI_floppy) ||
(info.devtype.interface != 0) /* XXX: needed ?? */)
continue;
err = config_man->get_size_of_current_configuration_for(cmcookie);
if (err < B_OK)
continue;
conf = (struct device_configuration *)malloc(err);
if (conf == NULL)
continue;
if (config_man->get_current_configuration_for(cmcookie, conf, err) < B_OK) {
free(conf);
continue;
}
master = &(floppies[current]);
for (i = 0; i < conf->num_resources; i++) {
if (conf->resources[i].type == B_IO_PORT_RESOURCE) {
int32 iobase = conf->resources[i].d.r.minbase;
int32 len = conf->resources[i].d.r.len;
/* WTF do I get
* min 3f2 max 3f2 align 0 len 4 ?
* on my K6-2, I even get 2 bytes at 3f2 + 2 bytes at 3f4 !
* looks like AT interface, suppose PS/2, which is 8 bytes wide.
* answer: because the 8th byte is also for the IDE controller...
* good old PC stuff... PPC here I come !
*/
// XXX: maybe we shouldn't use DIGITAL_IN if register window
// is only 6 bytes ?
if (len != 8) {
if ((master->iobase & 0xfffffff8) == 0x3f0)
iobase = 0x3f0;
else {
dprintf(FLO "controller has weird register window len %ld !?\n",
len);
break;
}
}
master->iobase = iobase;
}
if (conf->resources[i].type == B_IRQ_RESOURCE) {
int val;
for (val = 0; val < 32; val++) {
if (conf->resources[i].d.m.mask & (1 << val)) {
master->irq = val;
break;
}
}
}
if (conf->resources[i].type == B_DMA_RESOURCE) {
int val;
for (val = 0; val < 32; val++) {
if (conf->resources[i].d.m.mask & (1 << val)) {
master->dma = val;
break;
}
}
}
}
if (master->iobase == 0) {
dprintf(FLO "controller doesn't have any io ??\n");
goto config_error;
}
dprintf(FLO "controller at 0x%04lx, irq %ld, dma %ld\n",
master->iobase, master->irq, master->dma);
//master->dma = -1; // XXX: DEBUG: disable DMA
/* allocate resources */
master->completion = create_sem(0, "floppy interrupt");
if (master->completion < 0)
goto config_error;
new_lock(&master->ben, "floppy driver access");
//if (new_lock(&master->ben, "floppy driver access") < B_OK)
// goto config_error;
/* 20K should hold a full cylinder XXX: B_LOMEM for DMA ! */
master->buffer_area = create_area("floppy cylinder buffer", (void **)&master->buffer,
B_ANY_KERNEL_ADDRESS, CYL_BUFFER_SIZE,
B_FULL_LOCK, B_READ_AREA|B_WRITE_AREA);
if (master->buffer_area < B_OK)
goto config_error2;
B_INITIALIZE_SPINLOCK(&master->slock);
master->isa = isa;
if (install_io_interrupt_handler(master->irq, flo_intr, (void *)master, 0) < B_OK)
goto config_error2;
flops = count_floppies(master); /* actually a bitmap */
flops = MAX(flops, 1); /* XXX: assume at least one */
TRACE("drives found: 0x%01x\n", flops);
for (i = 0; current < MAX_FLOPPIES && i < 4; i++) {
if ((flops & (1 << i)) == 0)
continue;
floppies[current].next = NULL;
if (last)
last->next = &(floppies[current]);
floppies[current].iobase = master->iobase;
floppies[current].irq = master->irq;
floppies[current].dma = master->dma;
floppies[current].drive_num = i;
floppies[current].master = master;
floppies[current].isa = master->isa;
floppies[current].completion = master->completion;
floppies[current].track = -1;
last = &(floppies[current]);
current++;
}
/* XXX: TODO: remove "assume at least one" + cleanup if no drive on controller */
goto config_ok;
config_error2:
if (master->buffer_area)
delete_area(master->buffer_area);
free_lock(&master->ben);
config_error:
if (master->completion > 0)
delete_sem(master->completion);
master->iobase = 0;
put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME);
put_module(B_ISA_MODULE_NAME);
config_ok:
free(conf);
if (current >= MAX_FLOPPIES)
break;
}
/* make device names */
for (i = 0, j = 0; i < MAX_FLOPPIES; i++) {
if (floppies[i].iobase) {
#ifdef FIRST_ONE_NO_NUMBER
if (!i)
strcpy(floppy_dev_name[i], OLD_DEV_FORMAT);
else
#endif
sprintf(floppy_dev_name[i], DEV_FORMAT, i);
dev_names[j++] = floppy_dev_name[i];
TRACE("names[%d] = %s\n", j-1, dev_names[j-1]);
} else
strcpy(floppy_dev_name[i], "");
}
dev_names[j] = NULL;
#ifdef NEW_DEV_LAYOUT
#if !defined(NO_SYMLINK_OLD) && !defined(FIRST_ONE_NO_NUMBER)
/* fake the good old single drive */
mkdir("/dev/disk/floppy", 0755);
symlink("0/raw", "/dev/disk/floppy/raw");
#endif
#endif
return B_OK;
}
void
uninit_driver(void)
{
int i;
TRACE("uninit_driver()\n");
unregister_kernel_daemon(motor_off_daemon, floppies);
for (i = 0; i < MAX_FLOPPIES; i++) {
if (floppies[i].iobase)
turn_off_motor(&floppies[i]);
}
TRACE("deallocating...\n");
for (i = 0; i < MAX_FLOPPIES; i++) {
if (floppies[i].iobase) {
if (floppies[i].master == &(floppies[i])) {
remove_io_interrupt_handler(floppies[i].irq, flo_intr, (void *)&(floppies[i]));
free_lock(&floppies[i].ben);
delete_sem(floppies[i].completion);
delete_area(floppies[i].buffer_area);
}
}
}
TRACE("uninit done\n");
put_module(B_CONFIG_MANAGER_FOR_DRIVER_MODULE_NAME);
put_module(B_ISA_MODULE_NAME);
}
const char **
publish_devices(void)
{
if (dev_names[0] == NULL)
return NULL;
return dev_names;
}
device_hooks *
find_device(const char *name)
{
(void)name;
return &floppy_hooks;
}
static status_t
flo_open(const char *name, uint32 flags, floppy_cookie **cookie)
{
int i;
TRACE("open(%s)\n", name);
if (flags & O_NONBLOCK)
return EINVAL;
for (i = 0; i < MAX_FLOPPIES; i++) {
if (dev_names[i] && (strncmp(name, dev_names[i], strlen(dev_names[i])) == 0))
break;
}
if (i >= MAX_FLOPPIES)
return ENODEV;
*cookie = (floppy_cookie *)malloc(sizeof(floppy_cookie));
if (*cookie == NULL)
return B_NO_MEMORY;
(*cookie)->flp = &(floppies[i]);
/* if we don't know yet if there's something in, check that */
if ((*cookie)->flp->status <= FLOP_MEDIA_CHANGED)
query_media((*cookie)->flp, false);
return B_OK;
}
static status_t
flo_close(floppy_cookie *cookie)
{
TRACE("close()\n");
cookie->flp = NULL;
return B_OK;
}
static status_t
flo_free(floppy_cookie *cookie)
{
TRACE("free()\n");
free(cookie);
return B_OK;
}
static status_t
flo_read(floppy_cookie *cookie, off_t position, void *data, size_t *numbytes)
{
status_t err;
size_t len = *numbytes;
size_t bytes_read = 0;
int sectsize = SECTOR_SIZE;
int cylsize = TRACK_SIZE; /* hmm, badly named, it's actually track_size (a cylinder has 2 tracks, one per head) */
const device_geometry *geom = NULL;
ssize_t disk_size = 0;
if (cookie->flp->geometry)
geom = &cookie->flp->geometry->g;
if (geom) {
sectsize = geom->bytes_per_sector;
cylsize = sectsize * geom->sectors_per_track/* * geom->head_count*/;
disk_size = (geom->bytes_per_sector)
* (geom->sectors_per_track)
* (geom->head_count)
* (geom->cylinder_count);
}
if (disk_size <= 0) {
*numbytes = 0;
return B_DEV_NO_MEDIA;
}
if (position > disk_size) {
dprintf(FLO "attempt to seek beyond device end!\n");
*numbytes = 0;
return B_OK;
}
if (position + *numbytes > disk_size) {
dprintf(FLO "attempt to read beyond device end!\n");
*numbytes = (size_t)((off_t)disk_size - position);
if (*numbytes == 0)
return B_OK;
}
// handle partial first block
if ((position % SECTOR_SIZE) != 0) {
size_t toread;
TRACE("read: begin %Ld, %ld\n", position, bytes_read);
err = read_sectors(cookie->flp, position / sectsize, 1);
TRACE("PIO READ got %ld sect\n", err);
if (err <= 0) {
*numbytes = 0;
return err;
}
toread = MIN(len, (size_t)sectsize);
toread = MIN(toread, sectsize - (position % sectsize));
memcpy(data, cookie->flp->master->buffer + position % cylsize/*(sectsize * ) + (position % sectsize)*/, toread);
len -= toread;
bytes_read += toread;
position += toread;
}
// read the middle blocks
while (len >= (size_t)sectsize) {
TRACE("read: middle %Ld, %ld, %ld\n", position, bytes_read, len);
// try to read as many sectors as we can
err = read_sectors(cookie->flp, position / sectsize, len / sectsize);
TRACE("PIO READ got %ld sect\n", err);
if (err <= 0) {
*numbytes = 0;
return err;
}
memcpy(((char *)data) + bytes_read, cookie->flp->master->buffer + position % cylsize, err*sectsize);
len -= err * sectsize;
bytes_read += err * sectsize;
position += err * sectsize;
}
// handle partial last block
if (len > 0 && (len % sectsize) != 0) {
TRACE("read: end %Ld, %ld %ld\n", position, bytes_read, len);
err = read_sectors(cookie->flp, position / sectsize, 1);
TRACE("PIO READ got %ld sect\n", err);
if (err <= 0) {
*numbytes = 0;
return err;
}
memcpy(((char *)data) + bytes_read, cookie->flp->master->buffer + position % cylsize, len);
bytes_read += len;
position += len;
}
*numbytes = bytes_read;
return B_OK;
}
static status_t
flo_write(floppy_cookie *cookie, off_t position, const void *data, size_t *numbytes)
{
*numbytes = 0;
return B_ERROR;
}
static status_t
flo_control(floppy_cookie *cookie, uint32 op, void *data, size_t len)
{
device_geometry *geom;
status_t err;
floppy_t *flp = cookie->flp;
switch (op) {
case B_GET_ICON:
TRACE("control(B_GET_ICON, %ld)\n", ((device_icon *)data)->icon_size);
if (((device_icon *)data)->icon_size == 16) { /* mini icon */
memcpy(((device_icon *)data)->icon_data, floppy_mini_icon, (16*16));
return B_OK;
}
if (((device_icon *)data)->icon_size == 32) { /* icon */
memcpy(((device_icon *)data)->icon_data, floppy_icon, (32*32));
return B_OK;
}
return EINVAL;
case B_GET_BIOS_DRIVE_ID:
TRACE("control(B_GET_BIOS_DRIVE_ID)\n");
*(uint8 *)data = 0;
return B_OK;
case B_GET_DEVICE_SIZE:
TRACE("control(B_GET_DEVICE_SIZE)\n");
err = query_media(cookie->flp, true);
*(size_t *)data = (flp->bgeom.bytes_per_sector)
* (flp->bgeom.sectors_per_track)
* (flp->bgeom.head_count)
* (flp->bgeom.cylinder_count);
return B_OK;
case B_GET_GEOMETRY:
case B_GET_BIOS_GEOMETRY:
TRACE("control(B_GET_(BIOS)_GEOMETRY)\n");
err = query_media(cookie->flp, false);
geom = (device_geometry *)data;
geom->bytes_per_sector = flp->bgeom.bytes_per_sector;
geom->sectors_per_track = flp->bgeom.sectors_per_track;
geom->cylinder_count = flp->bgeom.cylinder_count;
geom->head_count = flp->bgeom.head_count;
geom->device_type = B_DISK;
geom->removable = true;
geom->read_only = flp->bgeom.read_only;
geom->write_once = false;
return B_OK;
case B_GET_MEDIA_STATUS:
TRACE("control(B_GET_MEDIA_STATUS)\n");
err = query_media(cookie->flp, false);
*(status_t *)data = err;
return B_OK;
}
TRACE("control(%ld)\n", op);
return EINVAL;
}
static void
motor_off_daemon(void *t, int tim)
{
int i;
for (i = 0; i < MAX_FLOPPIES; i++) {
if (floppies[i].iobase && !floppies[i].pending_cmd && floppies[i].motor_timeout > 0) {
TRACE("floppies[%d].motor_timeout = %ld\n", i, floppies[i].motor_timeout);
if (atomic_add((int32*)&floppies[i].motor_timeout, -500000) <= 500000) {
dprintf("turning off motor for drive %d\n", floppies[i].drive_num);
turn_off_motor(&floppies[i]);
floppies[i].motor_timeout = 0;
}
}
}
}
device_hooks floppy_hooks = {
(device_open_hook)flo_open,
(device_close_hook)flo_close,
(device_free_hook)flo_free,
(device_control_hook)flo_control,
(device_read_hook)flo_read,
(device_write_hook)flo_write,
NULL, /* select */
NULL, /* deselect */
NULL, /* readv */
NULL /* writev */
};

View File

@ -1,231 +0,0 @@
/*
* Copyright 2003-2008, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
#ifndef _FLOPPY_H
#define _FLOPPY_H
#include <Drivers.h>
#include <ISA.h>
#include <KernelExport.h>
// TODO: switch to native lock.
#ifdef __HAIKU__
#include <lock.h>
typedef recursive_lock lock;
#define new_lock recursive_lock_init
#define free_lock recursive_lock_destroy
#define LOCK(l) recursive_lock_lock(&l);
#define UNLOCK(l) recursive_lock_unlock(&l);
#else
#ifndef _IMPEXP_KERNEL
#define _IMPEXP_KERNEL
#endif
#include "lock.h"
#endif
#define FLO "floppy: "
#if defined(DEBUG) && DEBUG > 0
# define TRACE(x...) dprintf(FLO x)
#else
# define TRACE(x...)
#endif
#define MOTOR_TIMEOUT 5000000 // 5 seconds
#define MOTOR_SPINUP_DELAY 500000 // 500 msecs
#define FLOPPY_CMD_TIMEOUT 500000 // .5s
#define MAX_DRIVES_PER_CTRL 2
#define CYL_BUFFER_SIZE (5*B_PAGE_SIZE)
/*** those belong to ISA.h ***/
#define B_DMA_MODE_DEMAND 0x00 // modeByte bits for various dma modes
#define B_DMA_MODE_BLOCK 0x80
#define B_DMA_MODE_SINGLE 0x40
#define B_DMA_MODE_MEMR 0x08 // modeByte memory read or write
#define B_DMA_MODE_MEMW 0x04
/*** !ISA.h ***/
typedef enum {
FLOP_NO_MEDIA,
FLOP_MEDIA_CHANGED,
FLOP_MEDIA_UNREADABLE,
FLOP_MEDIA_FORMAT_FOUND,
FLOP_WORKING
} floppy_status;
#define CMD_MODE 0x01
#define CMD_SETTRK 0x21 //21
#define CMD_READTRK 0x02
#define CMD_SPECIFY 0x03
#define CMD_SENSED 0x04
#define CMD_WRITED 0x05
#define CMD_READD 0x06
#define CMD_RECAL 0x07
#define CMD_SENSEI 0x08
#define CMD_WRITEDD 0x09
#define CMD_READID 0x0A
#define CMD_READDD 0x0C
#define CMD_FORMAT 0x0D
#define CMD_DUMPREG 0x0E
#define CMD_SEEK 0x0F
#define CMD_RELSEEK 0x8F //8F
#define CMD_VERSION 0x10
#define CMD_SCANE 0x11
#define CMD_PERPEND 0x12
#define CMD_CONFIG 0x13
#define CMD_LOCK 0x14
#define CMD_VERIFY 0x16
#define CMD_SCANLE 0x19
#define CMD_SCANHE 0x1D
#define CMD_RESET 0xF0
#define CMD_SWITCH_MASK 0x1F
typedef struct floppy_geometry {
int gap;
int numsectors;
int data_rate;
int format_gap;
int side2_offset;
device_geometry g;
int flags;
const char *name;
} floppy_geometry;
extern const floppy_geometry supported_geometries[];
#define FL_MFM 0x0001 /* MFM recording */
#define FL_2STEP 0x0002 /* 2 steps between cylinders */
#define FL_PERP 0x0004 /* perpendicular recording */
#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
#define FDC_1MBPS 0x03 /* 1MPBS MFM drive transfer rate */
#define FDC_MAX_CYLINDER 85
typedef struct floppy {
const floppy_geometry *geometry;
device_geometry bgeom;
uint32 iobase; /* controller address */
uint32 irq;
int32 dma;
int drive_num; /* number of this drive */
int current; /* currently selected drive */
floppy_status status;
sem_id completion;
uint16 pending_cmd;
uint8 result[8]; /* status of the last finished command */
lock ben;
spinlock slock;
isa_module_info *isa;
uint8 data_rate; /* FDC_*BPS */
uint32 motor_timeout;
area_id buffer_area;
uint8 *buffer;
long buffer_index; /* index at which to put/get the next byte in the buffer */
long avail; /* valid bytes in the buffer */
int track; /* the track currently in the cylinder buffer */
struct floppy *master; /* the 'controller' */
struct floppy *next; /* next floppy for same controller */
} floppy_t;
typedef struct {
uint8 id;
uint8 drive;
uint8 cylinder;
uint8 head;
uint8 sector;
uint8 sector_size;
uint8 track_length;
uint8 gap3_length;
uint8 data_length;
} floppy_command;
typedef struct {
uint8 st0;
uint8 st1;
uint8 st2;
uint8 cylinder;
uint8 head;
uint8 sector;
uint8 sector_size;
} floppy_result;
typedef enum {
STATUS_A = 0,
STATUS_B = 1,
DIGITAL_OUT = 2,
TAPE_DRIVE = 3,
MAIN_STATUS = 4,
DATA_RATE_SELECT = 4,
DATA = 5,
/* RESERVED = 6, */
DIGITAL_IN = 7,
CONFIG_CONTROL = 7
} floppy_reg_selector;
#define FDC_SR0_IC 0xc0
#define FDC_SR0_SE 0x20
#define FDC_SR0_EC 0x10
#define FDC_SR0_HS 0x04
#define FDC_SR0_DS 0x03
/* low level */
extern void write_reg(floppy_t *flp, floppy_reg_selector selector, uint8 data);
extern uint8 read_reg(floppy_t *flp, floppy_reg_selector selector);
/* init */
/* initialize the controller */
extern void reset_controller(floppy_t *master);
/* returns a bitmap of the present drives */
extern int count_floppies(floppy_t *master);
/* seek to track 0 and detect drive presence */
extern int recalibrate_drive(floppy_t *flp);
/* debug */
/* issue dumpreg command */
extern void floppy_dump_reg(floppy_t *flp);
/* drive handling */
extern void drive_select(floppy_t *flp);
extern void drive_deselect(floppy_t *flp);
extern void turn_on_motor(floppy_t *flp);
extern void turn_off_motor(floppy_t *flp);
/* transactions */
extern void wait_for_rqm(floppy_t *flp);
extern bool can_read_result(floppy_t *flp);
/* send a command and schedule for irq */
extern int send_command(floppy_t *flp, const uint8 *data, int len);
extern int wait_til_ready(floppy_t *flp);
/* called by irq handler */
extern int read_result(floppy_t *flp, uint8 *data, int len);
/* wait for the irq to occur */
extern int wait_result(floppy_t *flp);
extern int32 flo_intr(void *arg);
/* read sectors to internal flp->master->buffer */
extern ssize_t pio_read_sectors(floppy_t *flp, int lba, int num_sectors);
/* write sectors from internal flp->master->buffer */
extern ssize_t pio_write_sectors(floppy_t *flp, int lba, int num_sectors);
/* read a track to internal flp->master->buffer */
extern ssize_t pio_read_track(floppy_t *flp, int lba);
/* high level */
/* query the media type and fill the geometry information */
extern status_t query_media(floppy_t *flp, bool forceupdate);
extern ssize_t read_sectors(floppy_t *flp, int lba, int num_sectors);
#endif /* _FLOPPY_H */

View File

@ -1,881 +0,0 @@
/*
* Copyright 2003-2008, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* François Revol <revol@free.fr>
*/
#include <Drivers.h>
#include "floppy.h"
/* VERY verbose... */
//#define DEBUG_LOWLEVEL
#if defined(DEBUG) && DEBUG > 0
# define PRINT_SR0(x) print_sr0(x)
#else
# define PRINT_SR0(x) ;
#endif
#if defined(DEBUG) && DEBUG > 0
static void
print_sr0(uint8 sr0)
{
const char *result = "ok";
switch (sr0 & FDC_SR0_IC) {
case 0x80:
result = "invalid";
break;
case 0x40:
result = "abterm";
break;
case 0xc0:
result = "drvchngd";
break;
}
TRACE("sr0: ds %d, hs %d, ec %d, se %d, %s\n", (sr0 & FDC_SR0_DS), !!(sr0 & FDC_SR0_HS), !!(sr0 & FDC_SR0_EC), !!(sr0 & FDC_SR0_SE), result);
}
#endif
void
write_reg(floppy_t *flp, floppy_reg_selector selector, uint8 data)
{
#ifdef DEBUG_LOWLEVEL
TRACE("write to 0x%lx, data 0x%x\n", flp->iobase + selector, data);
#endif
flp->isa->write_io_8(flp->iobase + selector, data);
}
uint8 read_reg(floppy_t *flp, floppy_reg_selector selector)
{
uint8 data;
data = flp->isa->read_io_8(flp->iobase + selector);
#ifdef DEBUG_LOWLEVEL
TRACE("read from 0x%lx = 0x%x\n", flp->iobase + selector, data);
#endif
return data;
}
void
reset_controller(floppy_t *master)
{
uint8 command[4]; /* for SPECIFY & CONFIGURE */
uint8 result[1]; /* for SPECIFY */
TRACE("reset_controller()\n");
LOCK(master->ben);
//master->pending_cmd = CMD_RESET;
master->pending_cmd = 0;
write_reg(master, DIGITAL_OUT, read_reg(master, DIGITAL_OUT) & ~0x04); /* reset */
//wait_result(master);
spin(20);
write_reg(master, DATA_RATE_SELECT, FDC_500KBPS); // 500 kbps
master->data_rate = FDC_500KBPS;
write_reg(master, DIGITAL_OUT, /*(master->dma < 0)?0x04:*//*0x0c*/0x04); /* motors[abcd] off, DMA on, deassert reset, drive select(0) */
wait_result(master); /* wait for reset interrupt */
command[0] = CMD_CONFIG; // configure command
command[1] = 0; // N/A
command[2] = 0x57;//0x70; // Implied Seek, FIFO, Poll Disable, THRESH = default
command[3] = 0; // PRETRK
send_command(master, command, sizeof(command));
command[0] = CMD_SPECIFY;
command[1] = (((16 - (3)) << 4) | ((240 / 16))); /* step rate 3ms, head unload time 240ms */
command[2] = 0x02 | 0x01; /* head load time 2ms, NO DMA */
send_command(master, command, 3); /* send SPECIFY */
read_result(master, result, 1);
UNLOCK(master->ben);
}
/* returns a bitmap of the present drives */
int
count_floppies(floppy_t *master)
{
int i, err;
int flops = 0;
master->master = master;
//floppy_dump_reg(master);
/* reset controller */
reset_controller(master);
for (i = 0; i < MAX_DRIVES_PER_CTRL; i++) {
master->drive_num = i; /* fake */
TRACE("DETECTING DRIVE %d...\n", i);
turn_on_motor(master);
drive_select(master);
err = recalibrate_drive(master);
if (err == 0)
flops |= 1 << i;
TRACE("DRIVE %d %s\n", i, err?"NOT here":"is here");
drive_deselect(master);
//snooze(50000);
//turn_off_motor(master);
}
// floppy_dump_reg(master);
master->drive_num = 0;
return flops;
}
/* selects the drive until deselect(), takes the benaphore */
void
drive_select(floppy_t *flp)
{
cpu_status st;
uint8 reg;
TRACE("drive_select(%d)\n", flp->drive_num);
LOCK(flp->master->ben);
/* must be atomic to not change motor states! */
st = disable_interrupts();
acquire_spinlock(&(flp->master->slock));
/* make sure the speed for this drive is correct */
if (flp->geometry && (flp->master->data_rate != flp->geometry->data_rate)) {
write_reg(flp, DATA_RATE_SELECT, flp->geometry->data_rate); // 500 kbps
flp->master->data_rate = flp->geometry->data_rate;
}
/* make sure the drive is selected and DMA is on */
reg = read_reg(flp, DIGITAL_OUT);
if((reg & 0x0b) != ((flp->drive_num & 0x03) | 0x08))
write_reg(flp, DIGITAL_OUT, (reg & 0xfc) | (flp->drive_num & 0x03) | /*(flp->master->dma < 0)?0x04:*/0x0c); /* DMA on, reset off */
release_spinlock(&(flp->master->slock));
restore_interrupts(st);
flp->master->current = flp->drive_num;
}
void
drive_deselect(floppy_t *flp)
{
UNLOCK(flp->master->ben);
TRACE("drive_deselect(%d)\n", flp->drive_num);
}
void
turn_on_motor(floppy_t *flp)
{
cpu_status st;
uint8 reg;
bool do_snooze = false;
TRACE("turn_on_motor(%d)\n", flp->drive_num);
flp->motor_timeout = MOTOR_TIMEOUT;
/* must be atomic to not deselect a drive! */
st = disable_interrupts();
acquire_spinlock(&(flp->master->slock));
if(((reg = read_reg(flp, DIGITAL_OUT)) & (0x10 << flp->drive_num)) == 0) {
/* it's off now, turn it on and wait */
//reg = 0x0c;
//reg &= 0xfc; /* mask out drive num */
write_reg(flp, DIGITAL_OUT, (0x10 << flp->drive_num) | reg);
do_snooze = true;
}
release_spinlock(&(flp->master->slock));
restore_interrupts(st);
if (do_snooze)
snooze(MOTOR_SPINUP_DELAY);
}
void
turn_off_motor(floppy_t *flp)
{
cpu_status st;
TRACE("turn_off_motor(%d)\n", flp->drive_num);
/* must be atomic to not deselect a drive! */
st = disable_interrupts();
acquire_spinlock(&(flp->master->slock));
write_reg(flp, DIGITAL_OUT, read_reg(flp, DIGITAL_OUT) & ~(0x10 << flp->drive_num));
//write_reg(flp, DIGITAL_OUT, 0x4);
flp->motor_timeout = 0;
release_spinlock(&(flp->master->slock));
restore_interrupts(st);
}
void
wait_for_rqm(floppy_t *flp)
{
while ((read_reg(flp, MAIN_STATUS) & 0x80) == 0);
}
int
send_command(floppy_t *flp, const uint8 *data, int len)
{
int i, status;
switch (data[0] & CMD_SWITCH_MASK) {
case CMD_SENSEI:
case CMD_SENSED:
case CMD_CONFIG:
case CMD_DUMPREG:
/* those don't generate an interrupt
* (SENSEI is sent by the intrrupt handler itself!)
*/
break;
default:
flp->pending_cmd = data[0];
}
for(i = 0; i < len; i++) {
status = wait_til_ready(flp);
if ((status < 0) || (status & 0x40))
break;
write_reg(flp, DATA, data[i]);
}
#ifdef DEBUG_LOWLEVEL
TRACE("sent %d B\n", i);
#endif
return i;
}
int
wait_result(floppy_t *flp) {
status_t err;
{ int32 c; get_sem_count(flp->completion, &c); TRACE("SEM< %ld\n", c); }
if ((err = acquire_sem_etc(flp->completion, 1, B_TIMEOUT, FLOPPY_CMD_TIMEOUT)) < B_OK) {
if (err == B_TIMED_OUT) {
cpu_status st;
TRACE("timed out! faking intr !!\n");
st = disable_interrupts();
flo_intr(flp);
restore_interrupts(st);
acquire_sem_etc(flp->completion, 1, B_TIMEOUT, FLOPPY_CMD_TIMEOUT);
}
return -1;
}
{ int32 c; get_sem_count(flp->completion, &c); TRACE("SEM> %ld\n", c); }
return 0;
}
int
read_result(floppy_t *flp, uint8 *data, int len)
{
int i, status;
//if (flp->master->need_reset)
// return -1;
for(i = 0; i < len; i++) {
status = wait_til_ready(flp);
if ((status < 0) || ((status & 0x40) == 0))
break;
data[i] = read_reg(flp, DATA);
}
//flp->master->need_reset = 1;
#ifdef DEBUG_LOWLEVEL
TRACE("read %d B\n", i);
#endif
return i;
}
int
wait_til_ready(floppy_t *flp)
{
int i, status;
for (i = 0; i < 1000; i++)
if ((status = read_reg(flp, MAIN_STATUS)) & 0x80)
return status;
TRACE("timeout waiting for %d !\n", flp->drive_num);
return -1;
}
#if 0
static int
has_drive_changed(floppy_t *flp)
{
return !!(read_reg(flp, DIGITAL_IN) & 0x80);
}
#endif
status_t
query_media(floppy_t *flp, bool forceupdate)
{
status_t err = B_OK;
uint8 command[4];
uint8 result[7] = {0};
const floppy_geometry *geom = NULL;
TRACE("query_media(%d, %s)\n", flp->drive_num, forceupdate?"true":"false");
turn_on_motor(flp);
drive_select(flp);
if (read_reg(flp, DIGITAL_IN) & 0x80) {/* media changed */
flp->status = FLOP_MEDIA_CHANGED;
TRACE("media changed\n");
}
if (err || (flp->status < FLOP_MEDIA_UNREADABLE) || forceupdate) {
geom = supported_geometries;
TRACE("querying format [err %08lx, st %d, fu %s]\n", err, flp->status, forceupdate?"t":"f");
/* zero the current geometry */
flp->geometry = 0;
flp->bgeom.bytes_per_sector = 255;
flp->bgeom.sectors_per_track = 0;
flp->bgeom.cylinder_count = 0;
flp->bgeom.head_count = 0;
flp->bgeom.read_only = true;
command[0] = 0x04; // sense drive command
command[1] = 0x00 | (flp->drive_num & 0x03); //
send_command(flp, command, 2);
read_result(flp, result, 1);
TRACE("sense_drive(%d): wp %d, trk0 %d, hd %d, drivesel %d\n", flp->drive_num, !!(result[0]&0x40), !!(result[0]&0x10), !!(result[0]&0x04), (result[0]&0x03));
flp->bgeom.read_only = !!(result[0]&0x40);
for (; geom->numsectors; geom++) {
TRACE("trying geometry %s\n", geom->name);
/* apply geometry parameters */
if (flp->master->data_rate != geom->data_rate) {
write_reg(flp, DATA_RATE_SELECT, geom->data_rate); // 500 kbps
flp->master->data_rate = geom->data_rate;
}
/* seek track 0, head 0 */
command[0] = 0x0f; // seek command
command[1] = (flp->drive_num & 0x03) | 0x00; // drive | head 0
command[2] = 0x00; // track 0
TRACE("SEEK at track 0 head 0\n");
send_command(flp, command, 3);
if (wait_result(flp) < 0)
continue;
/* if it went there then there si something, even if we can't read it */
flp->status = FLOP_MEDIA_UNREADABLE;
//command[0] = 8; // sense interrupt command
//send_command(flp, command, 1);
//read_result(flp, result, 2); // read the result
PRINT_SR0(flp->result[0]);
TRACE("track is %d\n", flp->result[1]);
if (flp->result[0] & FDC_SR0_IC)
continue;
command[0] = 0x0a | ((geom->flags&FL_MFM)?0x40:0); // read track id
command[1] = (flp->drive_num & 0x03) | 0x00; // drive | head 0
TRACE("READ_TRACK_ID\n");
send_command(flp, command, 2);
if (wait_result(flp) < 0)
continue;
//read_result(flp, result, 7);
PRINT_SR0(flp->result[0]);
TRACE("sr1: %02x\n", flp->result[1]);
TRACE("sr2: %02x\n", flp->result[2]);
TRACE("read id: track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]);
if (flp->result[0] & FDC_SR0_IC)
continue;
/* seek track 2, head 1 */
command[0] = 0x0f; // seek command
command[1] = (flp->drive_num & 0x03) | 0x04; // drive | head 1
command[2] = 0x02; // track 2
TRACE("SEEK at track 2 head 1\n");
send_command(flp, command, 3);
if (wait_result(flp) < 0)
continue;
//command[0] = 8; // sense interrupt command
//send_command(flp, command, 1);
//read_result(flp, result, 2); // read the result
PRINT_SR0(flp->result[0]);
TRACE("track is %d\n", flp->result[1]);
if (flp->result[0] & FDC_SR0_IC)
continue;
command[0] = 0x0a | ((geom->flags&FL_MFM)?0x40:0); // read track id
command[1] = (flp->drive_num & 0x03) | 0x00; // drive | head 0
TRACE("READ_TRACK_ID\n");
send_command(flp, command, 2);
if (wait_result(flp) < 0)
continue;
//read_result(flp, result, 7);
//read_result(flp, result, 7);
PRINT_SR0(flp->result[0]);
TRACE("sr1: %02x\n", flp->result[1]);
TRACE("sr2: %02x\n", flp->result[2]);
TRACE("read id: track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]);
if (flp->result[0] & FDC_SR0_IC)
continue;
break;
}
if (geom->numsectors) {
dprintf(FLO "drive %d: media type is %s\n", flp->drive_num, geom->name);
flp->status = FLOP_MEDIA_FORMAT_FOUND;
err = B_OK;
flp->geometry = geom;
flp->bgeom.bytes_per_sector = geom->g.bytes_per_sector;
flp->bgeom.sectors_per_track = geom->g.sectors_per_track;
flp->bgeom.cylinder_count = geom->g.cylinder_count;
flp->bgeom.head_count = geom->g.head_count;
//flp->bgeom.read_only = true;
} else {
flp->status = FLOP_NO_MEDIA;
}
}
switch (flp->status) {
case FLOP_NO_MEDIA:
err = B_DEV_NO_MEDIA;
break;
case FLOP_MEDIA_CHANGED:
err = B_DEV_MEDIA_CHANGED;
break;
case FLOP_MEDIA_UNREADABLE:
err = B_DEV_UNREADABLE;
break;
case FLOP_MEDIA_FORMAT_FOUND:
case FLOP_WORKING:
default:
err = B_OK;
}
drive_deselect(flp);
return err;
}
int
recalibrate_drive(floppy_t *flp)
{
int retry;
TRACE("recalibrate_drive(%d)\n", flp->drive_num);
turn_on_motor(flp);
for(retry = 0; retry < 1; retry++) {
uint8 command[2] = { 7, 0 }; // recalibrate command
command[1] = flp->drive_num & 0x03;
// send the recalibrate command
send_command(flp, command, sizeof(command));
if (wait_result(flp) < 0)
return 3;
//command[0] = 8; // sense interrupt command
//send_command(flp, command, 1);
// read the result
//read_result(flp, result, sizeof(result));
if (flp->result[0] & 0xd0) {
TRACE("recalibration failed\n");
return 2;
} if (flp->result[1] != 0) {
TRACE("drive is at cylinder %d, didn't make it to 0\n", flp->result[1]);
if (retry > 3)
return 1;
} else {
// successful
break;
}
}
TRACE("recalibration done\n");
return 0;
}
int32
flo_intr(void *arg)
{
int i;
int len;
int32 err = B_UNHANDLED_INTERRUPT;
floppy_t *flp = (floppy_t *)arg;
floppy_t *master = flp->master;
if (master ==NULL)
return B_UNHANDLED_INTERRUPT;
acquire_spinlock(&master->slock);
while (flp && (flp->drive_num != master->current) && !flp->pending_cmd)
flp = flp->next;
if (flp) {
uint8 msr;
int got = 0;
msr = read_reg(flp, MAIN_STATUS);
//TRACE("got irq for %d! MSR=%02x\n", flp->drive_num, msr);
if ((((flp->pending_cmd & CMD_SWITCH_MASK) == CMD_READD) ||
((flp->pending_cmd & CMD_SWITCH_MASK) == CMD_READTRK)) && ((msr & 0x60) == 0x60)) {
/* non DMA xfer(data) & need read */
/* uint8 command[1];
command[0] = CMD_SENSEI;
send_command(flp, command, 1);
len = read_result(flp, flp->result, 2);
PRINT_SR0(flp->result[0]);*/
//TRACE("READi\n");
// while ((msr & 0x60) == 0x60 /*&& (got < 256)*/) {
while ((msr & 0xF0) == 0xF0 && (master->buffer_index < CYL_BUFFER_SIZE)) {
master->buffer[master->buffer_index++] = read_reg(flp, DATA);
master->avail++;
msr = read_reg(flp, MAIN_STATUS);
got++;
// spin(10);
/* if (got < 30)
TRACE("%02x", msr);
else
spin(15);*/
// if (got > 255)
// break;
}
// TRACE("intr: READ %d\n", got);
} else if (((flp->pending_cmd & CMD_SWITCH_MASK) == CMD_WRITED) && ((msr & 0x60) == 0x20)) {
/* non DMA xfer(data) & need write */
TRACE("WRITEi\n");
} else {
len = 8;
// if (flp->pending_cmd != CMD_RESET)
len = read_result(flp, flp->result, len);
// else
// len = 0;
if (len < 0) {
TRACE("buggy interrupt from %d !\n", flp->drive_num);
} else if (len < 1) { /* must pool the interrupt reason */
uint8 command[1] = { CMD_SENSEI };
for (i = 0; i < 4; i++) { /* might have to issue 4 SENSEI */
TRACE("intr: %dth SENSEI\n", i+1);
if (send_command(flp, command, 1) < 1)
break;
len = read_result(flp, flp->result, 2);
if (len > 0)
PRINT_SR0(flp->result[0]);
if (len != 2)
break;
if ((flp->result[0] & (0x80|FDC_SR0_DS)) == master->current)
break;
}
} else
TRACE("RES(%d) %02x %02x %02x %02x\n", len, flp->result[0], flp->result[1], flp->result[2], flp->result[3]);
/* only do that for !READ && !WRITE */
flp->pending_cmd = 0;
release_sem_etc(flp->completion, 1, B_DO_NOT_RESCHEDULE);
}
err = B_HANDLED_INTERRUPT;
}
release_spinlock(&master->slock);
if (err == B_UNHANDLED_INTERRUPT)
TRACE("unhandled irq!\n");
return err;
}
void
floppy_dump_reg(floppy_t *flp) {
uint8 command[1] = { 0x0e }; // dumpreg command
//uint8 result[10];
uint8 *result = flp->result;
send_command(flp, command, sizeof(command));
//wait_result(flp);
read_result(flp, result, 8);
dprintf(FLO "dumpreg: tracks - d1=%d d2=%d d3=%d d4=%d\n",
result[0], result[1], result[2], result[3]);
dprintf(FLO "dumpreg: step_rate_time=%d motor_off_time=%d motor_on_time=%d dma=%d\n",
result[4] >> 4, result[4] & 0x0f, result[5] >> 1, result[5] & 0x01);
dprintf(FLO "sec_per_trk/end_of_trk=0x%.2x lock=%d, byte[7]=0x%.2x\n",
result[6], result[7] >> 7,result[7]);
dprintf(FLO "gap=%d wg=%d eis=%d fifo=%d poll=%d thresh=%d pretrk=%d\n",
(result[7] & 0x02) >> 1, result[7] & 0x01, (result[8] & 0x40) >> 6,
(result[8] & 0x20) >> 5, (result[8] & 0x10) >> 4, result[8] & 0x0f, result[9]);
}
static void
fill_command_from_lba(floppy_t *flp, floppy_command *cmd, int lba)
{
cmd->cylinder = lba / (flp->bgeom.sectors_per_track * flp->bgeom.head_count);
cmd->head = (lba / flp->bgeom.sectors_per_track) % flp->bgeom.head_count;
cmd->sector = lba % flp->bgeom.sectors_per_track + 1;
cmd->drive = (flp->drive_num & 0x3) | (cmd->head << 2) | 0x80; /* Implied Seek */
}
/* does NOT check for valid track number */
ssize_t
pio_read_sectors(floppy_t *flp, /*void *buf,*/ int lba, int num_sectors)
{
ssize_t transfered = 0;
floppy_command cmd;
#if 0
uint8 cmd2[8];
uint8 result[4];
#endif
//floppy_result res;
if (flp->status < FLOP_MEDIA_FORMAT_FOUND)
return B_DEV_UNREADABLE;
turn_on_motor(flp);
drive_select(flp);
if (flp->geometry == NULL || !flp->bgeom.bytes_per_sector || !flp->bgeom.sectors_per_track) {
drive_deselect(flp);
return B_DEV_NO_MEDIA;
}
flp->track = -1;
num_sectors = MIN(num_sectors, (signed)(flp->bgeom.sectors_per_track - (lba % flp->bgeom.sectors_per_track)));
cmd.id = CMD_READD | /*0xc0*/0x40; // multi-track, read MFM, one head
cmd.sector_size = 2; /* 512 bytes */
cmd.track_length = num_sectors;//flp->bgeom.sectors_per_track;
cmd.gap3_length = flp->geometry->gap; //27; /* 3.5" floppy */
cmd.data_length = 0xff; /* don't care */
fill_command_from_lba(flp, &cmd, lba);
dprintf(FLO "pio_read_sector(%d, %d={%d,%d,%d}, %d)\n", flp->drive_num, lba, cmd.cylinder, cmd.head, cmd.sector, num_sectors);
if (num_sectors < 1) {
drive_deselect(flp);
return EINVAL;
}
//num_sectors = 1;
#if 0
/* first issue sense interrupt, to find the current track */
TRACE("track check: SENSEI\n");
cmd2[0] = CMD_SENSEI;
send_command(flp, cmd2, 1);
read_result(flp, result, 2);
PRINT_SR0(result[0]);
/* if the current track is not the one we want, seek */
if (result[1] != cmd.cylinder) {
/* seek */
cmd2[0] = CMD_SEEK; // seek command
cmd2[1] = (flp->drive_num & 0x3) | (cmd.head << 2);
cmd2[2] = cmd.cylinder; // track 0
TRACE("SEEK at track %d head %d\n", cmd.cylinder, cmd.head);
send_command(flp, cmd2, 3);
if (wait_result(flp) < 0)
return ENXIO;
}
#endif
flp->master->avail = 0;
flp->master->buffer_index = (lba % (flp->bgeom.sectors_per_track/* * flp->bgeom.head_count*/)) * flp->bgeom.bytes_per_sector;
//flp->pending_cmd = CMD_READD;
send_command(flp, (uint8 *)&cmd, sizeof(cmd));
if (wait_result(flp) < 0) {
drive_deselect(flp);
return ENXIO;
}
PRINT_SR0(flp->result[0]);
TRACE("sr1: %02x\n", flp->result[1]);
TRACE("sr2: %02x\n", flp->result[2]);
TRACE("@ track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]);
switch (flp->result[0] & FDC_SR0_IC) {
case 0x80:
transfered = EINVAL;
break;
case 0x40:
//if (flp->result[1] != 0x80) /* End Of Track is not really an error, actually it means it worked :) */
// transfered = ENXIO;
break;
case 0xc0:
transfered = B_DEV_MEDIA_CHANGED;
break;
}
if (transfered) {
drive_deselect(flp);
return ENXIO;
}
/* normal termination */
transfered = flp->avail;
/* if (transfered > 0)
memcpy(buf, flp->buffer, flp->avail);*/
drive_deselect(flp);
return num_sectors;//transfered;
}
ssize_t
pio_write_sectors(floppy_t *flp, /*const void *buf,*/ int lba, int num_sectors)
{
return -1;
}
/* does NOT check for valid track number */
ssize_t
pio_read_track(floppy_t *flp, /*void *buf,*/ int lba)
{
ssize_t transfered = 0;
floppy_command cmd;
#if 0
uint8 cmd2[8];
uint8 result[4];
#endif
int tries = 0;
if (flp->status < FLOP_MEDIA_FORMAT_FOUND)
return B_DEV_UNREADABLE;
turn_on_motor(flp);
drive_select(flp);
if (flp->geometry == NULL || !flp->bgeom.bytes_per_sector || !flp->bgeom.sectors_per_track) {
drive_deselect(flp);
return B_DEV_NO_MEDIA;
}
flp->track = -1;
retry_track:
//num_sectors = MIN(num_sectors, (signed)(flp->bgeom.sectors_per_track - (lba % flp->bgeom.sectors_per_track)));
cmd.id = CMD_READTRK | 0x40; // read MFM
cmd.sector_size = 2; /* 512 bytes */
cmd.track_length = flp->bgeom.sectors_per_track;
cmd.gap3_length = flp->geometry->gap; //27; /* 3.5" floppy */
cmd.data_length = 0xff; /* don't care */
fill_command_from_lba(flp, &cmd, lba);
cmd.sector = 1;
dprintf(FLO "pio_read_track(%d, %d={%d,%d,%d}) try %d\n", flp->drive_num, lba, cmd.cylinder, cmd.head, cmd.sector, tries);
#if 0
/* first issue sense interrupt, to find the current track */
TRACE("track check: SENSEI\n");
cmd2[0] = CMD_SENSEI;
send_command(flp, cmd2, 1);
read_result(flp, result, 2);
PRINT_SR0(result[0]);
/* if the current track is not the one we want, seek */
if (result[1] != cmd.cylinder) {
/* seek */
cmd2[0] = CMD_SEEK; // seek command
cmd2[1] = (flp->drive_num & 0x3) | (cmd.head << 2);
cmd2[2] = cmd.cylinder; // track 0
TRACE("SEEK at track %d head %d\n", cmd.cylinder, cmd.head);
send_command(flp, cmd2, 3);
if (wait_result(flp) < 0)
return ENXIO;
}
#endif
flp->master->avail = 0;
flp->master->buffer_index = 0;//(lba % (flp->bgeom.sectors_per_track * flp->bgeom.head_count)) * flp->bgeom.bytes_per_sector;
send_command(flp, (uint8 *)&cmd, sizeof(cmd));
if (wait_result(flp) < 0) {
drive_deselect(flp);
return ENXIO;
}
PRINT_SR0(flp->result[0]);
TRACE("sr1: %02x\n", flp->result[1]);
TRACE("sr2: %02x\n", flp->result[2]);
TRACE("@ track %d, head %d, sec %d, bps %d\n", flp->result[3], flp->result[4], flp->result[5], flp->result[6]);
switch (flp->result[0] & FDC_SR0_IC) {
case 0x80:
transfered = EINVAL;
break;
case 0x40:
TRACE(FLO "sr1: %02x\n", flp->result[1]);
if (flp->result[1] != 0x80) {/* End Of Track is not really an error, actually it means it worked :) */
if (/*(flp->result[1] == 0x10) && */tries < 3) { /* overrun */
tries++;
goto retry_track;
} else
transfered = EIO;
}
break;
case 0xc0:
transfered = B_DEV_MEDIA_CHANGED;
break;
}
if (transfered) {
drive_deselect(flp);
return ENXIO;
}
/* normal termination */
transfered = flp->avail;
/* if (transfered > 0)
memcpy(buf, flp->buffer, flp->avail);*/
flp->master->track = cmd.cylinder*flp->bgeom.head_count + cmd.head;
drive_deselect(flp);
return 1;//transfered;
}
ssize_t
read_sectors(floppy_t *flp, int lba, int num_sectors)
{
ssize_t transfered = 0;
//return pio_read_sectors(flp, lba, num_sectors);
/* if (nothing cached || not the same track cached) */
dprintf(FLO "read_sector(%d, %d, %d)\n", flp->drive_num, lba, num_sectors);
num_sectors = MIN(num_sectors, (signed)(flp->bgeom.sectors_per_track - (lba % flp->bgeom.sectors_per_track)));
if ((flp->master->track < 0) ||
(flp->master->track != (signed)(lba / (flp->bgeom.sectors_per_track)))) {
if ((lba / (flp->bgeom.sectors_per_track)) >= (flp->bgeom.head_count * flp->bgeom.cylinder_count))
return ENXIO;
transfered = pio_read_track(flp, lba);
if (transfered < 0)
return transfered;
/* XXX: TODO: in case of IO error, retry by single sector */
}
return num_sectors;
}

View File

@ -1,37 +0,0 @@
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#ifndef _LOCK_H
#define _LOCK_H
#include <BeBuild.h>
#include <OS.h>
typedef struct lock lock;
typedef struct mlock mlock;
struct lock {
sem_id s;
long c;
};
struct mlock {
sem_id s;
};
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
extern _IMPEXP_KERNEL int free_lock(lock *l);
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
#endif