Subject: [PATCH] m68k: Add support for ARAnyM block and console access From: Roman Zippel Add support for ARAnyM block and console access Signed-off-by: Roman Zippel Signed-off-by: Geert Uytterhoeven --- arch/m68k/Kconfig | 16 ++++ arch/m68k/emu/Makefile | 2 arch/m68k/emu/natfeat.c | 38 ---------- arch/m68k/emu/nfblock.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ arch/m68k/emu/nfcon.c | 164 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 362 insertions(+), 38 deletions(-) --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -285,6 +285,22 @@ config NFETH which will emulate a regular ethernet device while presenting an ethertap device to the host system. +config NFBLOCK + tristate "NatFeat block device support" + depends on BLOCK && NATFEAT + help + Say Y to include support for the ARAnyM NatFeat block device + which allows direct access to the hard drives without using + the hardware emulation. + +config NFCON + tristate "NatFeat console driver" + depends on NATFEAT + help + Say Y to include support for the ARAnyM NatFeat console driver + which allows the console output to be redirected to the stderr + output of ARAnyM. + comment "Processor type" config M68020 --- a/arch/m68k/emu/Makefile +++ b/arch/m68k/emu/Makefile @@ -5,3 +5,5 @@ obj-y += natfeat.o obj-$(CONFIG_NFETH) += nfeth.o +obj-$(CONFIG_NFBLOCK) += nfblock.o +obj-$(CONFIG_NFCON) += nfcon.o --- a/arch/m68k/emu/natfeat.c +++ b/arch/m68k/emu/natfeat.c @@ -32,24 +32,6 @@ asm("\n" " .long nf_call,1b\n" " .previous"); -static int stderr_id; - -static void nf_write(struct console *co, const char *str, unsigned int count) -{ - char buf[68]; - - buf[64] = 0; - while (count > 64) { - memcpy(buf, str, 64); - nf_call(stderr_id, buf); - str += 64; - count -= 64; - } - memcpy(buf, str, count); - buf[count] = 0; - nf_call(stderr_id, buf); -} - void nfprint(const char *fmt, ...) { static char buf[256]; @@ -62,26 +44,6 @@ void nfprint(const char *fmt, ...) va_end(ap); } -static struct console nf_console_driver = { - .name = "debug", - .write = nf_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init nf_debug_setup(char *arg) -{ - if (strcmp(arg, "emu")) - return 0; - - stderr_id = nf_get_id("NF_STDERR"); - if (stderr_id) - register_console(&nf_console_driver); - return 0; -} - -early_param("debug", nf_debug_setup); - static void nf_poweroff(void) { long id = nf_get_id("NF_SHUTDOWN"); --- /dev/null +++ b/arch/m68k/emu/nfblock.c @@ -0,0 +1,180 @@ +/* + * ARAnyM block device driver + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +static long nfhd_id; + +enum { + /* emulation entry points */ + NFHD_READ_WRITE = 10, + NFHD_GET_CAPACITY = 14, + + /* skip ACSI devices */ + NFHD_DEV_OFFSET = 8, +}; + +static LIST_HEAD(nfhd_list); + +static int major_num; +module_param(major_num, int, 0); + +struct nfhd_device { + struct list_head list; + int id; + u32 blocks, bsize; + int bshift; + struct request_queue *queue; + struct gendisk *disk; +}; + +static int nfhd_make_request(struct request_queue *queue, struct bio *bio) +{ + struct nfhd_device *dev = queue->queuedata; + struct bio_vec *bvec; + int i, dir, len, shift; + sector_t sec = bio->bi_sector; + + dir = bio_data_dir(bio); + shift = dev->bshift; + bio_for_each_segment(bvec, bio, i) { + len = bvec->bv_len; + len >>= 9; + nf_call(nfhd_id + NFHD_READ_WRITE, dev->id, 0, dir, + sec >> shift, len >> shift, bvec_to_phys(bvec)); + sec += len; + } + bio_endio(bio, 0); + return 0; +} + +int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct nfhd_device *dev = bdev->bd_disk->private_data; + + geo->cylinders = dev->blocks >> (6 - dev->bshift); + geo->heads = 4; + geo->sectors = 16; + + return 0; +} + +static struct block_device_operations nfhd_ops = { + .owner = THIS_MODULE, + .getgeo = nfhd_getgeo, +}; + +static int __init nfhd_init_one(int id, u32 blocks, u32 bsize) +{ + struct nfhd_device *dev; + int dev_id = id - NFHD_DEV_OFFSET; + + printk(KERN_INFO "nfhd%u: found device with %u blocks (%u bytes)\n", + dev_id, blocks, bsize); + + if (bsize < 512 || (bsize & (bsize - 1))) { + printk(KERN_WARNING "nfhd%u: invalid block size\n", dev_id); + return -EINVAL; + } + + dev = kmalloc(sizeof(struct nfhd_device), GFP_KERNEL); + if (!dev) + goto out; + + dev->id = id; + dev->blocks = blocks; + dev->bsize = bsize; + dev->bshift = ffs(bsize) - 10; + + dev->queue = blk_alloc_queue(GFP_KERNEL); + if (dev->queue == NULL) + goto free_dev; + + dev->queue->queuedata = dev; + blk_queue_make_request(dev->queue, nfhd_make_request); + blk_queue_hardsect_size(dev->queue, bsize); + + dev->disk = alloc_disk(16); + if (!dev->disk) + goto free_queue; + + dev->disk->major = major_num; + dev->disk->first_minor = dev_id * 16; + dev->disk->fops = &nfhd_ops; + dev->disk->private_data = dev; + sprintf(dev->disk->disk_name, "nfhd%u", dev_id); + set_capacity(dev->disk, (sector_t)blocks * (bsize / 512)); + dev->disk->queue = dev->queue; + + add_disk(dev->disk); + + list_add_tail(&dev->list, &nfhd_list); + + return 0; + +free_queue: + blk_cleanup_queue(dev->queue); +free_dev: + kfree(dev); +out: + return -ENOMEM; +} + +static int __init nfhd_init(void) +{ + u32 blocks, bsize; + int i; + + nfhd_id = nf_get_id("XHDI"); + if (!nfhd_id) + return -ENODEV; + + major_num = register_blkdev(major_num, "nfhd"); + if (major_num <= 0) { + printk(KERN_WARNING "nfhd: unable to get major number\n"); + return -ENODEV; + } + + for (i = NFHD_DEV_OFFSET; i < 24; i++) { + if (nf_call(nfhd_id + NFHD_GET_CAPACITY, i, 0, &blocks, &bsize)) + continue; + nfhd_init_one(i, blocks, bsize); + } + + return 0; +} + +static void __exit nfhd_exit(void) +{ + struct nfhd_device *dev, *next; + + list_for_each_entry_safe(dev, next, &nfhd_list, list) { + list_del(&dev->list); + del_gendisk(dev->disk); + put_disk(dev->disk); + blk_cleanup_queue(dev->queue); + kfree(dev); + } + unregister_blkdev(major_num, "nfhd"); +} + +module_init(nfhd_init); +module_exit(nfhd_exit); + +MODULE_LICENSE("GPL"); --- /dev/null +++ b/arch/m68k/emu/nfcon.c @@ -0,0 +1,164 @@ +/* + * ARAnyM console driver + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int stderr_id; +static struct tty_driver *nfcon_tty_driver; + +static void nfcon_write(struct console *con, const char *str, unsigned int count) +{ + char buf[68]; + + buf[64] = 0; + while (count > 64) { + memcpy(buf, str, 64); + nf_call(stderr_id, buf); + str += 64; + count -= 64; + } + memcpy(buf, str, count); + buf[count] = 0; + nf_call(stderr_id, buf); +} + +struct tty_driver *nfcon_device(struct console *con, int *index) +{ + *index = 0; + return (con->flags & CON_ENABLED) ? nfcon_tty_driver : NULL; +} + +static struct console nf_console = { + .name = "nfcon", + .write = nfcon_write, + .device = nfcon_device, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + + +static int nfcon_tty_open(struct tty_struct *tty, struct file *filp) +{ + return 0; +} + +static void nfcon_tty_close(struct tty_struct *tty, struct file *filp) +{ +} + +static int nfcon_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + char temp[68]; + int i = count; + + temp[64] = 0; + while (i > 64) { + memcpy(temp, buf, 64); + nf_call(stderr_id, temp); + buf += 64; + i -= 64; + } + memcpy(temp, buf, i); + temp[i] = 0; + nf_call(stderr_id, temp); + + return count; +} + +static int nfcon_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + char temp[2] = { ch, 0 }; + + nf_call(stderr_id, temp); + return 1; +} + +static int nfcon_tty_write_room(struct tty_struct *tty) +{ + return 64; +} + +static const struct tty_operations nfcon_tty_ops = { + .open = nfcon_tty_open, + .close = nfcon_tty_close, + .write = nfcon_tty_write, + .put_char = nfcon_tty_put_char, + .write_room = nfcon_tty_write_room, +}; + +static int __init nf_debug_setup(char *arg) +{ + if (strcmp(arg, "nfcon")) + return 0; + + stderr_id = nf_get_id("NF_STDERR"); + if (stderr_id) { + nf_console.flags |= CON_ENABLED; + register_console(&nf_console); + } + + return 0; +} + +early_param("debug", nf_debug_setup); + +static int __init nfcon_init(void) +{ + int res; + + stderr_id = nf_get_id("NF_STDERR"); + if (!stderr_id) + return -ENODEV; + + nfcon_tty_driver = alloc_tty_driver(1); + if (!nfcon_tty_driver) + return -ENOMEM; + + nfcon_tty_driver->owner = THIS_MODULE; + nfcon_tty_driver->driver_name = "nfcon"; + nfcon_tty_driver->name = "nfcon"; + nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; + nfcon_tty_driver->subtype = SYSTEM_TYPE_TTY; + nfcon_tty_driver->init_termios = tty_std_termios; + nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW; + + tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops); + res = tty_register_driver(nfcon_tty_driver); + if (res) { + printk(KERN_ERR "failed to register nfcon tty driver\n"); + put_tty_driver(nfcon_tty_driver); + return res; + } + + if (!(nf_console.flags & CON_ENABLED)) + register_console(&nf_console); + + return 0; +} + +static void __exit nfcon_exit(void) +{ + unregister_console(&nf_console); + tty_unregister_driver(nfcon_tty_driver); + put_tty_driver(nfcon_tty_driver); +} + +module_init(nfcon_init); +module_exit(nfcon_exit); + +MODULE_LICENSE("GPL");