mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
9
arch/m68k/emu/Makefile
Normal file
9
arch/m68k/emu/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for Linux arch/m68k/emu source directory
|
||||
#
|
||||
|
||||
obj-y += natfeat.o
|
||||
|
||||
obj-$(CONFIG_NFBLOCK) += nfblock.o
|
||||
obj-$(CONFIG_NFCON) += nfcon.o
|
||||
obj-$(CONFIG_NFETH) += nfeth.o
|
94
arch/m68k/emu/natfeat.c
Normal file
94
arch/m68k/emu/natfeat.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* natfeat.c - ARAnyM hardware support via Native Features (natfeats)
|
||||
*
|
||||
* Copyright (c) 2005 Petr Stehlik of ARAnyM dev team
|
||||
*
|
||||
* Reworked for Linux by Roman Zippel <zippel@linux-m68k.org>
|
||||
*
|
||||
* This software may be used and distributed according to the terms of
|
||||
* the GNU General Public License (GPL), incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/natfeat.h>
|
||||
|
||||
extern long nf_get_id_phys(unsigned long feature_name);
|
||||
|
||||
asm("\n"
|
||||
" .global nf_get_id_phys,nf_call\n"
|
||||
"nf_get_id_phys:\n"
|
||||
" .short 0x7300\n"
|
||||
" rts\n"
|
||||
"nf_call:\n"
|
||||
" .short 0x7301\n"
|
||||
" rts\n"
|
||||
"1: moveq.l #0,%d0\n"
|
||||
" rts\n"
|
||||
" .section __ex_table,\"a\"\n"
|
||||
" .long nf_get_id_phys,1b\n"
|
||||
" .long nf_call,1b\n"
|
||||
" .previous");
|
||||
EXPORT_SYMBOL_GPL(nf_call);
|
||||
|
||||
long nf_get_id(const char *feature_name)
|
||||
{
|
||||
/* feature_name may be in vmalloc()ed memory, so make a copy */
|
||||
char name_copy[32];
|
||||
size_t n;
|
||||
|
||||
n = strlcpy(name_copy, feature_name, sizeof(name_copy));
|
||||
if (n >= sizeof(name_copy))
|
||||
return 0;
|
||||
|
||||
return nf_get_id_phys(virt_to_phys(name_copy));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_get_id);
|
||||
|
||||
void nfprint(const char *fmt, ...)
|
||||
{
|
||||
static char buf[256];
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(buf, 256, fmt, ap);
|
||||
nf_call(nf_get_id("NF_STDERR"), virt_to_phys(buf));
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void nf_poweroff(void)
|
||||
{
|
||||
long id = nf_get_id("NF_SHUTDOWN");
|
||||
|
||||
if (id)
|
||||
nf_call(id);
|
||||
}
|
||||
|
||||
void __init nf_init(void)
|
||||
{
|
||||
unsigned long id, version;
|
||||
char buf[256];
|
||||
|
||||
id = nf_get_id("NF_VERSION");
|
||||
if (!id)
|
||||
return;
|
||||
version = nf_call(id);
|
||||
|
||||
id = nf_get_id("NF_NAME");
|
||||
if (!id)
|
||||
return;
|
||||
nf_call(id, virt_to_phys(buf), 256);
|
||||
buf[255] = 0;
|
||||
|
||||
pr_info("NatFeats found (%s, %lu.%lu)\n", buf, version >> 16,
|
||||
version & 0xffff);
|
||||
|
||||
mach_power_off = nf_poweroff;
|
||||
}
|
195
arch/m68k/emu/nfblock.c
Normal file
195
arch/m68k/emu/nfblock.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/natfeat.h>
|
||||
|
||||
static long nfhd_id;
|
||||
|
||||
enum {
|
||||
/* emulation entry points */
|
||||
NFHD_READ_WRITE = 10,
|
||||
NFHD_GET_CAPACITY = 14,
|
||||
|
||||
/* skip ACSI devices */
|
||||
NFHD_DEV_OFFSET = 8,
|
||||
};
|
||||
|
||||
static inline s32 nfhd_read_write(u32 major, u32 minor, u32 rwflag, u32 recno,
|
||||
u32 count, u32 buf)
|
||||
{
|
||||
return nf_call(nfhd_id + NFHD_READ_WRITE, major, minor, rwflag, recno,
|
||||
count, buf);
|
||||
}
|
||||
|
||||
static inline s32 nfhd_get_capacity(u32 major, u32 minor, u32 *blocks,
|
||||
u32 *blocksize)
|
||||
{
|
||||
return nf_call(nfhd_id + NFHD_GET_CAPACITY, major, minor,
|
||||
virt_to_phys(blocks), virt_to_phys(blocksize));
|
||||
}
|
||||
|
||||
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 void nfhd_make_request(struct request_queue *queue, struct bio *bio)
|
||||
{
|
||||
struct nfhd_device *dev = queue->queuedata;
|
||||
struct bio_vec bvec;
|
||||
struct bvec_iter iter;
|
||||
int dir, len, shift;
|
||||
sector_t sec = bio->bi_iter.bi_sector;
|
||||
|
||||
dir = bio_data_dir(bio);
|
||||
shift = dev->bshift;
|
||||
bio_for_each_segment(bvec, bio, iter) {
|
||||
len = bvec.bv_len;
|
||||
len >>= 9;
|
||||
nfhd_read_write(dev->id, 0, dir, sec >> shift, len >> shift,
|
||||
bvec_to_phys(&bvec));
|
||||
sec += len;
|
||||
}
|
||||
bio_endio(bio, 0);
|
||||
}
|
||||
|
||||
static 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 const 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;
|
||||
|
||||
pr_info("nfhd%u: found device with %u blocks (%u bytes)\n", dev_id,
|
||||
blocks, bsize);
|
||||
|
||||
if (bsize < 512 || (bsize & (bsize - 1))) {
|
||||
pr_warn("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_logical_block_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) {
|
||||
pr_warn("nfhd: unable to get major number\n");
|
||||
return major_num;
|
||||
}
|
||||
|
||||
for (i = NFHD_DEV_OFFSET; i < 24; i++) {
|
||||
if (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");
|
169
arch/m68k/emu/nfcon.c
Normal file
169
arch/m68k/emu/nfcon.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/natfeat.h>
|
||||
|
||||
static int stderr_id;
|
||||
static struct tty_port nfcon_tty_port;
|
||||
static struct tty_driver *nfcon_tty_driver;
|
||||
|
||||
static void nfputs(const char *str, unsigned int count)
|
||||
{
|
||||
char buf[68];
|
||||
unsigned long phys = virt_to_phys(buf);
|
||||
|
||||
buf[64] = 0;
|
||||
while (count > 64) {
|
||||
memcpy(buf, str, 64);
|
||||
nf_call(stderr_id, phys);
|
||||
str += 64;
|
||||
count -= 64;
|
||||
}
|
||||
memcpy(buf, str, count);
|
||||
buf[count] = 0;
|
||||
nf_call(stderr_id, phys);
|
||||
}
|
||||
|
||||
static void nfcon_write(struct console *con, const char *str,
|
||||
unsigned int count)
|
||||
{
|
||||
nfputs(str, count);
|
||||
}
|
||||
|
||||
static 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)
|
||||
{
|
||||
nfputs(buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int nfcon_tty_put_char(struct tty_struct *tty, unsigned char ch)
|
||||
{
|
||||
char temp[2] = { ch, 0 };
|
||||
|
||||
nf_call(stderr_id, virt_to_phys(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,
|
||||
};
|
||||
|
||||
#ifndef MODULE
|
||||
|
||||
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);
|
||||
|
||||
#endif /* !MODULE */
|
||||
|
||||
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;
|
||||
|
||||
tty_port_init(&nfcon_tty_port);
|
||||
|
||||
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);
|
||||
tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
|
||||
res = tty_register_driver(nfcon_tty_driver);
|
||||
if (res) {
|
||||
pr_err("failed to register nfcon tty driver\n");
|
||||
put_tty_driver(nfcon_tty_driver);
|
||||
tty_port_destroy(&nfcon_tty_port);
|
||||
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);
|
||||
tty_port_destroy(&nfcon_tty_port);
|
||||
}
|
||||
|
||||
module_init(nfcon_init);
|
||||
module_exit(nfcon_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
271
arch/m68k/emu/nfeth.c
Normal file
271
arch/m68k/emu/nfeth.c
Normal file
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux
|
||||
*
|
||||
* Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team
|
||||
*
|
||||
* Based on ARAnyM driver for FreeMiNT written by Standa Opichal
|
||||
*
|
||||
* This software may be used and distributed according to the terms of
|
||||
* the GNU General Public License (GPL), incorporated herein by reference.
|
||||
*/
|
||||
|
||||
#define DRV_VERSION "0.3"
|
||||
#define DRV_RELDATE "10/12/2005"
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/natfeat.h>
|
||||
#include <asm/virtconvert.h>
|
||||
|
||||
enum {
|
||||
GET_VERSION = 0,/* no parameters, return NFAPI_VERSION in d0 */
|
||||
XIF_INTLEVEL, /* no parameters, return Interrupt Level in d0 */
|
||||
XIF_IRQ, /* acknowledge interrupt from host */
|
||||
XIF_START, /* (ethX), called on 'ifup', start receiver thread */
|
||||
XIF_STOP, /* (ethX), called on 'ifdown', stop the thread */
|
||||
XIF_READLENGTH, /* (ethX), return size of network data block to read */
|
||||
XIF_READBLOCK, /* (ethX, buffer, size), read block of network data */
|
||||
XIF_WRITEBLOCK, /* (ethX, buffer, size), write block of network data */
|
||||
XIF_GET_MAC, /* (ethX, buffer, size), return MAC HW addr in buffer */
|
||||
XIF_GET_IPHOST, /* (ethX, buffer, size), return IP address of host */
|
||||
XIF_GET_IPATARI,/* (ethX, buffer, size), return IP address of atari */
|
||||
XIF_GET_NETMASK /* (ethX, buffer, size), return IP netmask */
|
||||
};
|
||||
|
||||
#define MAX_UNIT 8
|
||||
|
||||
/* These identify the driver base version and may not be removed. */
|
||||
static const char version[] =
|
||||
KERN_INFO KBUILD_MODNAME ".c:v" DRV_VERSION " " DRV_RELDATE
|
||||
" S.Opichal, M.Jurik, P.Stehlik\n"
|
||||
KERN_INFO " http://aranym.org/\n";
|
||||
|
||||
MODULE_AUTHOR("Milan Jurik");
|
||||
MODULE_DESCRIPTION("Atari NFeth driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
/*
|
||||
MODULE_PARM(nfeth_debug, "i");
|
||||
MODULE_PARM_DESC(nfeth_debug, "nfeth_debug level (1-2)");
|
||||
*/
|
||||
|
||||
|
||||
static long nfEtherID;
|
||||
static int nfEtherIRQ;
|
||||
|
||||
struct nfeth_private {
|
||||
int ethX;
|
||||
};
|
||||
|
||||
static struct net_device *nfeth_dev[MAX_UNIT];
|
||||
|
||||
static int nfeth_open(struct net_device *dev)
|
||||
{
|
||||
struct nfeth_private *priv = netdev_priv(dev);
|
||||
int res;
|
||||
|
||||
res = nf_call(nfEtherID + XIF_START, priv->ethX);
|
||||
netdev_dbg(dev, "%s: %d\n", __func__, res);
|
||||
|
||||
/* Ready for data */
|
||||
netif_start_queue(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfeth_stop(struct net_device *dev)
|
||||
{
|
||||
struct nfeth_private *priv = netdev_priv(dev);
|
||||
|
||||
/* No more data */
|
||||
netif_stop_queue(dev);
|
||||
|
||||
nf_call(nfEtherID + XIF_STOP, priv->ethX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a packet out of the adapter and pass it to the upper layers
|
||||
*/
|
||||
static inline void recv_packet(struct net_device *dev)
|
||||
{
|
||||
struct nfeth_private *priv = netdev_priv(dev);
|
||||
unsigned short pktlen;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* read packet length (excluding 32 bit crc) */
|
||||
pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX);
|
||||
|
||||
netdev_dbg(dev, "%s: %u\n", __func__, pktlen);
|
||||
|
||||
if (!pktlen) {
|
||||
netdev_dbg(dev, "%s: pktlen == 0\n", __func__);
|
||||
dev->stats.rx_errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
skb = dev_alloc_skb(pktlen + 2);
|
||||
if (!skb) {
|
||||
netdev_dbg(dev, "%s: out of mem (buf_alloc failed)\n",
|
||||
__func__);
|
||||
dev->stats.rx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
skb->dev = dev;
|
||||
skb_reserve(skb, 2); /* 16 Byte align */
|
||||
skb_put(skb, pktlen); /* make room */
|
||||
nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data),
|
||||
pktlen);
|
||||
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
netif_rx(skb);
|
||||
dev->last_rx = jiffies;
|
||||
dev->stats.rx_packets++;
|
||||
dev->stats.rx_bytes += pktlen;
|
||||
|
||||
/* and enqueue packet */
|
||||
return;
|
||||
}
|
||||
|
||||
static irqreturn_t nfeth_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
int i, m, mask;
|
||||
|
||||
mask = nf_call(nfEtherID + XIF_IRQ, 0);
|
||||
for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) {
|
||||
if (mask & m && nfeth_dev[i]) {
|
||||
recv_packet(nfeth_dev[i]);
|
||||
nf_call(nfEtherID + XIF_IRQ, m);
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int nfeth_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
unsigned int len;
|
||||
char *data, shortpkt[ETH_ZLEN];
|
||||
struct nfeth_private *priv = netdev_priv(dev);
|
||||
|
||||
data = skb->data;
|
||||
len = skb->len;
|
||||
if (len < ETH_ZLEN) {
|
||||
memset(shortpkt, 0, ETH_ZLEN);
|
||||
memcpy(shortpkt, data, len);
|
||||
data = shortpkt;
|
||||
len = ETH_ZLEN;
|
||||
}
|
||||
|
||||
netdev_dbg(dev, "%s: send %u bytes\n", __func__, len);
|
||||
nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data),
|
||||
len);
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += len;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nfeth_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
dev->stats.tx_errors++;
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
static const struct net_device_ops nfeth_netdev_ops = {
|
||||
.ndo_open = nfeth_open,
|
||||
.ndo_stop = nfeth_stop,
|
||||
.ndo_start_xmit = nfeth_xmit,
|
||||
.ndo_tx_timeout = nfeth_tx_timeout,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
};
|
||||
|
||||
static struct net_device * __init nfeth_probe(int unit)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct nfeth_private *priv;
|
||||
char mac[ETH_ALEN], host_ip[32], local_ip[32];
|
||||
int err;
|
||||
|
||||
if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac),
|
||||
ETH_ALEN))
|
||||
return NULL;
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct nfeth_private));
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
dev->irq = nfEtherIRQ;
|
||||
dev->netdev_ops = &nfeth_netdev_ops;
|
||||
|
||||
memcpy(dev->dev_addr, mac, ETH_ALEN);
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
priv->ethX = unit;
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
free_netdev(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nf_call(nfEtherID + XIF_GET_IPHOST, unit,
|
||||
virt_to_phys(host_ip), sizeof(host_ip));
|
||||
nf_call(nfEtherID + XIF_GET_IPATARI, unit,
|
||||
virt_to_phys(local_ip), sizeof(local_ip));
|
||||
|
||||
netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip,
|
||||
local_ip, mac);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int __init nfeth_init(void)
|
||||
{
|
||||
long ver;
|
||||
int error, i;
|
||||
|
||||
nfEtherID = nf_get_id("ETHERNET");
|
||||
if (!nfEtherID)
|
||||
return -ENODEV;
|
||||
|
||||
ver = nf_call(nfEtherID + GET_VERSION);
|
||||
pr_info("API %lu\n", ver);
|
||||
|
||||
nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL);
|
||||
error = request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED,
|
||||
"eth emu", nfeth_interrupt);
|
||||
if (error) {
|
||||
pr_err("request for irq %d failed %d", nfEtherIRQ, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_UNIT; i++)
|
||||
nfeth_dev[i] = nfeth_probe(i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nfeth_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_UNIT; i++) {
|
||||
if (nfeth_dev[i]) {
|
||||
unregister_netdev(nfeth_dev[0]);
|
||||
free_netdev(nfeth_dev[0]);
|
||||
}
|
||||
}
|
||||
free_irq(nfEtherIRQ, nfeth_interrupt);
|
||||
}
|
||||
|
||||
module_init(nfeth_init);
|
||||
module_exit(nfeth_cleanup);
|
Loading…
Add table
Add a link
Reference in a new issue