#define REALLY_SLOW_IO
#define DEBUGT …
#define DPRINT(format, args...) …
#define DCL_DEBUG …
#ifdef DCL_DEBUG
#define debug_dcl(test, fmt, args...) …
#else
#define debug_dcl …
#endif
static int print_unex = …;
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/fdreg.h>
#include <linux/fd.h>
#include <linux/hdreg.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/string.h>
#include <linux/jiffies.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/async.h>
#include <linux/compat.h>
static DEFINE_MUTEX(floppy_mutex);
static int slow_floppy;
#include <asm/dma.h>
#include <asm/irq.h>
static int FLOPPY_IRQ = …;
static int FLOPPY_DMA = …;
static int can_use_virtual_dma = …;
static int use_virtual_dma;
static DEFINE_SPINLOCK(floppy_lock);
static unsigned short virtual_dma_port = …;
irqreturn_t floppy_interrupt(int irq, void *dev_id);
static int set_dor(int fdc, char mask, char data);
#define K_64 …
static int allowed_drive_mask = …;
#include <asm/floppy.h>
static int irqdma_allocated;
#include <linux/blk-mq.h>
#include <linux/blkpg.h>
#include <linux/cdrom.h>
#include <linux/completion.h>
static LIST_HEAD(floppy_reqs);
static struct request *current_req;
static int set_next_request(void);
#ifndef fd_get_dma_residue
#define fd_get_dma_residue …
#endif
#ifndef fd_dma_mem_free
#define fd_dma_mem_free …
#endif
#ifndef fd_dma_mem_alloc
#define fd_dma_mem_alloc …
#endif
#ifndef fd_cacheflush
#define fd_cacheflush(addr, size) …
#endif
static inline void fallback_on_nodma_alloc(char **addr, size_t l)
{ … }
static unsigned long fake_change;
static bool initialized;
#define ITYPE(x) …
#define TOMINOR(x) …
#define UNIT(x) …
#define FDC(x) …
#define REVDRIVE(fdc, unit) …
#define PH_HEAD(floppy, head) …
#define STRETCH(floppy) …
#define COMMAND …
#define DR_SELECT …
#define TRACK …
#define HEAD …
#define SECTOR …
#define SIZECODE …
#define SECT_PER_TRACK …
#define GAP …
#define SIZECODE2 …
#define NR_RW …
#define F_SIZECODE …
#define F_SECT_PER_TRACK …
#define F_GAP …
#define F_FILL …
#define NR_F …
#define MAX_DISK_SIZE …
static unsigned char reply_buffer[FD_RAW_REPLY_SIZE];
static int inr;
#define ST0 …
#define ST1 …
#define ST2 …
#define ST3 …
#define R_TRACK …
#define R_HEAD …
#define R_SECTOR …
#define R_SIZECODE …
#define SEL_DLY …
static struct { … } default_drive_params[] = …;
static struct floppy_drive_params drive_params[N_DRIVE];
static struct floppy_drive_struct drive_state[N_DRIVE];
static struct floppy_write_errors write_errors[N_DRIVE];
static struct timer_list motor_off_timer[N_DRIVE];
static struct blk_mq_tag_set tag_sets[N_DRIVE];
static struct gendisk *opened_disk[N_DRIVE];
static DEFINE_MUTEX(open_lock);
static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
static struct floppy_struct floppy_type[32] = …;
static struct gendisk *disks[N_DRIVE][ARRAY_SIZE(floppy_type)];
#define SECTSIZE …
static struct floppy_struct *current_type[N_DRIVE];
static struct floppy_struct user_params[N_DRIVE];
static sector_t floppy_sizes[256];
static char floppy_device_name[] = …;
static int probing;
#define FD_COMMAND_NONE …
#define FD_COMMAND_ERROR …
#define FD_COMMAND_OKAY …
static volatile int command_status = …;
static unsigned long fdc_busy;
static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
static DECLARE_WAIT_QUEUE_HEAD(command_done);
static int floppy_errors;
static struct format_descr format_req;
static char *floppy_track_buffer;
static int max_buffer_sectors;
static const struct cont_t { … } *cont;
static void floppy_ready(void);
static void floppy_start(void);
static void process_fd_request(void);
static void recalibrate_floppy(void);
static void floppy_shutdown(struct work_struct *);
static int floppy_request_regions(int);
static void floppy_release_regions(int);
static int floppy_grab_irq_and_dma(void);
static void floppy_release_irq_and_dma(void);
static void reset_fdc(void);
static int floppy_revalidate(struct gendisk *disk);
#define NO_TRACK …
#define NEED_1_RECAL …
#define NEED_2_RECAL …
static atomic_t usage_count = …;
static int buffer_track = …;
static int buffer_drive = …;
static int buffer_min = …;
static int buffer_max = …;
static struct floppy_fdc_state fdc_state[N_FDC];
static int current_fdc;
static struct workqueue_struct *floppy_wq;
static struct floppy_struct *_floppy = …;
static unsigned char current_drive;
static long current_count_sectors;
static unsigned char fsector_t;
static unsigned char in_sector_offset;
static inline unsigned char fdc_inb(int fdc, int reg)
{ … }
static inline void fdc_outb(unsigned char value, int fdc, int reg)
{ … }
static inline bool drive_no_geom(int drive)
{ … }
#ifndef fd_eject
static inline int fd_eject(int drive)
{ … }
#endif
#ifdef DEBUGT
static long unsigned debugtimer;
static inline void set_debugt(void)
{ … }
static inline void debugt(const char *func, const char *msg)
{ … }
#else
static inline void set_debugt(void) { }
static inline void debugt(const char *func, const char *msg) { }
#endif
static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
static const char *timeout_message;
static void is_alive(const char *func, const char *message)
{ … }
static void (*do_floppy)(void) = …;
#define OLOGSIZE …
static void (*lasthandler)(void);
static unsigned long interruptjiffies;
static unsigned long resultjiffies;
static int resultsize;
static unsigned long lastredo;
static struct output_log { … } output_log[OLOGSIZE];
static int output_log_pos;
#define MAXTIMEOUT …
static void __reschedule_timeout(int drive, const char *message)
{ … }
static void reschedule_timeout(int drive, const char *message)
{ … }
#define INFBOUND(a, b) …
#define SUPBOUND(a, b) …
static int disk_change(int drive)
{ … }
static inline int is_selected(int dor, int unit)
{ … }
static bool is_ready_state(int status)
{ … }
static int set_dor(int fdc, char mask, char data)
{ … }
static void twaddle(int fdc, int drive)
{ … }
static void reset_fdc_info(int fdc, int mode)
{ … }
static void set_fdc(int drive)
{ … }
static int lock_fdc(int drive)
{ … }
static void unlock_fdc(void)
{ … }
static void motor_off_callback(struct timer_list *t)
{ … }
static void floppy_off(unsigned int drive)
{ … }
static void scandrives(void)
{ … }
static void empty(void)
{ … }
static void empty_done(int result)
{ … }
static void (*floppy_work_fn)(void);
static void floppy_work_workfn(struct work_struct *work)
{ … }
static DECLARE_WORK(floppy_work, floppy_work_workfn);
static void schedule_bh(void (*handler)(void))
{ … }
static void (*fd_timer_fn)(void) = …;
static void fd_timer_workfn(struct work_struct *work)
{ … }
static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
static void cancel_activity(void)
{ … }
static void fd_watchdog(void)
{ … }
static void main_command_interrupt(void)
{ … }
static int fd_wait_for_completion(unsigned long expires,
void (*function)(void))
{ … }
static void setup_DMA(void)
{ … }
static void show_floppy(int fdc);
static int wait_til_ready(int fdc)
{ … }
static int output_byte(int fdc, char byte)
{ … }
static int result(int fdc)
{ … }
#define MORE_OUTPUT …
static int need_more_output(int fdc)
{ … }
static void perpendicular_mode(int fdc)
{ … }
static int fifo_depth = …;
static int no_fifo;
static int fdc_configure(int fdc)
{ … }
#define NOMINAL_DTR …
static void fdc_specify(int fdc, int drive)
{ … }
static int fdc_dtr(void)
{ … }
static void tell_sector(void)
{ … }
static void print_errors(void)
{ … }
static int interpret_errors(void)
{ … }
static void setup_rw_floppy(void)
{ … }
static int blind_seek;
static void seek_interrupt(void)
{ … }
static void check_wp(int fdc, int drive)
{ … }
static void seek_floppy(void)
{ … }
static void recal_interrupt(void)
{ … }
static void print_result(char *message, int inr)
{ … }
irqreturn_t floppy_interrupt(int irq, void *dev_id)
{ … }
static void recalibrate_floppy(void)
{ … }
static void reset_interrupt(void)
{ … }
static void reset_fdc(void)
{ … }
static void show_floppy(int fdc)
{ … }
static void floppy_shutdown(struct work_struct *arg)
{ … }
static int start_motor(void (*function)(void))
{ … }
static void floppy_ready(void)
{ … }
static void floppy_start(void)
{ … }
static void do_wakeup(void)
{ … }
static const struct cont_t wakeup_cont = …;
static const struct cont_t intr_cont = …;
static int wait_til_done(void (*handler)(void), bool interruptible)
{ … }
static void generic_done(int result)
{ … }
static void generic_success(void)
{ … }
static void generic_failure(void)
{ … }
static void success_and_wakeup(void)
{ … }
static int next_valid_format(int drive)
{ … }
static void bad_flp_intr(void)
{ … }
static void set_floppy(int drive)
{ … }
static void format_interrupt(void)
{ … }
#define FM_MODE(x, y) …
#define CT(x) …
static void setup_format_params(int track)
{ … }
static void redo_format(void)
{ … }
static const struct cont_t format_cont = …;
static int do_format(int drive, struct format_descr *tmp_format_req)
{ … }
static void floppy_end_request(struct request *req, blk_status_t error)
{ … }
static void request_done(int uptodate)
{ … }
static void rw_interrupt(void)
{ … }
static int transfer_size(int ssize, int max_sector, int max_size)
{ … }
static void copy_buffer(int ssize, int max_sector, int max_sector_2)
{ … }
static void virtualdmabug_workaround(void)
{ … }
static int make_raw_rw_request(void)
{ … }
static int set_next_request(void)
{ … }
static void redo_fd_request(void)
{ … }
static const struct cont_t rw_cont = …;
static void process_fd_request(void)
{ … }
static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *bd)
{ … }
static const struct cont_t poll_cont = …;
static int poll_drive(bool interruptible, int flag)
{ … }
static void reset_intr(void)
{ … }
static const struct cont_t reset_cont = …;
static int user_reset_fdc(int drive, int arg, bool interruptible)
{ … }
static inline int fd_copyout(void __user *param, const void *address,
unsigned long size)
{ … }
static inline int fd_copyin(void __user *param, void *address,
unsigned long size)
{ … }
static const char *drive_name(int type, int drive)
{ … }
#ifdef CONFIG_BLK_DEV_FD_RAWCMD
static void raw_cmd_done(int flag)
{ … }
static const struct cont_t raw_cmd_cont = …;
static int raw_cmd_copyout(int cmd, void __user *param,
struct floppy_raw_cmd *ptr)
{ … }
static void raw_cmd_free(struct floppy_raw_cmd **ptr)
{ … }
#define MAX_LEN …
static int raw_cmd_copyin(int cmd, void __user *param,
struct floppy_raw_cmd **rcmd)
{ … }
static int raw_cmd_ioctl(int cmd, void __user *param)
{ … }
static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
void __user *param)
{ … }
#else
static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
void __user *param)
{
return -EOPNOTSUPP;
}
#endif
static int invalidate_drive(struct gendisk *disk)
{ … }
static int set_geometry(unsigned int cmd, struct floppy_struct *g,
int drive, int type, struct block_device *bdev)
{ … }
static unsigned int ioctl_table[] = …;
static int normalize_ioctl(unsigned int *cmd, int *size)
{ … }
static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
{ … }
static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{ … }
static bool valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE],
int native_format)
{ … }
static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param)
{ … }
static int fd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param)
{ … }
#ifdef CONFIG_COMPAT
struct compat_floppy_drive_params { … };
struct compat_floppy_drive_struct { … };
struct compat_floppy_fdc_state { … };
struct compat_floppy_write_errors { … };
#define FDSETPRM32 …
#define FDDEFPRM32 …
#define FDSETDRVPRM32 …
#define FDGETDRVPRM32 …
#define FDGETDRVSTAT32 …
#define FDPOLLDRVSTAT32 …
#define FDGETFDCSTAT32 …
#define FDWERRORGET32 …
static int compat_set_geometry(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, struct compat_floppy_struct __user *arg)
{ … }
static int compat_get_prm(int drive,
struct compat_floppy_struct __user *arg)
{ … }
static int compat_setdrvprm(int drive,
struct compat_floppy_drive_params __user *arg)
{ … }
static int compat_getdrvprm(int drive,
struct compat_floppy_drive_params __user *arg)
{ … }
static int compat_getdrvstat(int drive, bool poll,
struct compat_floppy_drive_struct __user *arg)
{ … }
static int compat_getfdcstat(int drive,
struct compat_floppy_fdc_state __user *arg)
{ … }
static int compat_werrorget(int drive,
struct compat_floppy_write_errors __user *arg)
{ … }
static int fd_compat_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param)
{ … }
#endif
static void __init config_types(void)
{ … }
static void floppy_release(struct gendisk *disk)
{ … }
static int floppy_open(struct gendisk *disk, blk_mode_t mode)
{ … }
static unsigned int floppy_check_events(struct gendisk *disk,
unsigned int clearing)
{ … }
struct rb0_cbdata { … };
static void floppy_rb0_cb(struct bio *bio)
{ … }
static int __floppy_read_block_0(struct block_device *bdev, int drive)
{ … }
static int floppy_revalidate(struct gendisk *disk)
{ … }
static const struct block_device_operations floppy_fops = …;
static char __init get_fdc_version(int fdc)
{ … }
static void __init floppy_set_flags(int *ints, int param, int param2)
{ … }
static void __init daring(int *ints, int param, int param2)
{ … }
static void __init set_cmos(int *ints, int dummy, int dummy2)
{ … }
static struct param_table { … } config_params[] __initdata = …;
static int __init floppy_setup(char *str)
{ … }
static int have_no_fdc = …;
static ssize_t floppy_cmos_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR(cmos, 0444, floppy_cmos_show, NULL);
static struct attribute *floppy_dev_attrs[] = …;
ATTRIBUTE_GROUPS(…);
static void floppy_device_release(struct device *dev)
{ … }
static int floppy_resume(struct device *dev)
{ … }
static const struct dev_pm_ops floppy_pm_ops = …;
static struct platform_driver floppy_driver = …;
static const struct blk_mq_ops floppy_mq_ops = …;
static struct platform_device floppy_device[N_DRIVE];
static bool registered[N_DRIVE];
static bool floppy_available(int drive)
{ … }
static int floppy_alloc_disk(unsigned int drive, unsigned int type)
{ … }
static DEFINE_MUTEX(floppy_probe_lock);
static void floppy_probe(dev_t dev)
{ … }
static int __init do_floppy_init(void)
{ … }
#ifndef MODULE
static __init void floppy_async_init(void *data, async_cookie_t cookie)
{ … }
#endif
static int __init floppy_init(void)
{ … }
static const struct io_region { … } io_regions[] = …;
static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
{ … }
#define ARRAY_END(X) …
static int floppy_request_regions(int fdc)
{ … }
static void floppy_release_regions(int fdc)
{ … }
static int floppy_grab_irq_and_dma(void)
{ … }
static void floppy_release_irq_and_dma(void)
{ … }
#ifdef MODULE
static char *floppy;
static void __init parse_floppy_cfg_string(char *cfg)
{
char *ptr;
while (*cfg) {
ptr = cfg;
while (*cfg && *cfg != ' ' && *cfg != '\t')
cfg++;
if (*cfg) {
*cfg = '\0';
cfg++;
}
if (*ptr)
floppy_setup(ptr);
}
}
static int __init floppy_module_init(void)
{
if (floppy)
parse_floppy_cfg_string(floppy);
return floppy_init();
}
module_init(floppy_module_init);
static void __exit floppy_module_exit(void)
{
int drive, i;
unregister_blkdev(FLOPPY_MAJOR, "fd");
platform_driver_unregister(&floppy_driver);
destroy_workqueue(floppy_wq);
for (drive = 0; drive < N_DRIVE; drive++) {
del_timer_sync(&motor_off_timer[drive]);
if (floppy_available(drive)) {
for (i = 0; i < ARRAY_SIZE(floppy_type); i++) {
if (disks[drive][i])
del_gendisk(disks[drive][i]);
}
if (registered[drive])
platform_device_unregister(&floppy_device[drive]);
}
for (i = 0; i < ARRAY_SIZE(floppy_type); i++) {
if (disks[drive][i])
put_disk(disks[drive][i]);
}
blk_mq_free_tag_set(&tag_sets[drive]);
}
cancel_delayed_work_sync(&fd_timeout);
cancel_delayed_work_sync(&fd_timer);
if (atomic_read(&usage_count))
floppy_release_irq_and_dma();
fd_eject(0);
}
module_exit(floppy_module_exit);
module_param(floppy, charp, 0);
module_param(FLOPPY_IRQ, int, 0);
module_param(FLOPPY_DMA, int, 0);
MODULE_AUTHOR("Alain L. Knaff");
MODULE_DESCRIPTION("Normal floppy disk support");
MODULE_LICENSE("GPL");
static const struct pnp_device_id floppy_pnpids[] = {
{"PNP0700", 0},
{}
};
MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
#else
__setup(…);
module_init(…) …
#endif
MODULE_ALIAS_BLOCKDEV_MAJOR(…);