Commit 7f13c9f8 authored by Stephen Hemminger's avatar Stephen Hemminger

[PATCH] hamradio/scc -

Update hamradio/scc for 2.6.0-test5
	- use seq_file for /proc
	- get rid of dev_get()
	- use alloc_netdev

Don't have hardware, but can load/unload the module fine.
parent 5f179911
......@@ -171,6 +171,7 @@
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/ax25.h>
......@@ -202,8 +203,8 @@ static void scc_key_trx (struct scc_channel *scc, char tx);
static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
static void scc_init_timer(struct scc_channel *scc);
static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev);
static int scc_net_init(struct net_device *dev);
static int scc_net_alloc(const char *name, struct scc_channel *scc);
static void scc_net_setup(struct net_device *dev);
static int scc_net_open(struct net_device *dev);
static int scc_net_close(struct net_device *dev);
static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb);
......@@ -235,7 +236,7 @@ static io_port Vector_Latch;
/* These provide interrupt save 2-step access to the Z8530 registers */
static spinlock_t iolock; /* Guards paired accesses */
static spinlock_t iolock = SPIN_LOCK_UNLOCKED; /* Guards paired accesses */
static inline unsigned char InReg(io_port port, unsigned char reg)
{
......@@ -1512,34 +1513,28 @@ static void z8530_init(void)
* Allocate device structure, err, instance, and register driver
*/
static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev)
static int scc_net_alloc(const char *name, struct scc_channel *scc)
{
int err;
struct net_device *dev;
if (dev_get(name))
{
printk(KERN_INFO "Z8530drv: device %s already exists.\n", name);
return -EEXIST;
}
if ((scc->dev = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL)
dev = alloc_netdev(0, name, scc_net_setup);
if (!dev)
return -ENOMEM;
dev = scc->dev;
memset(dev, 0, sizeof(struct net_device));
strcpy(dev->name, name);
dev->priv = (void *) scc;
dev->init = scc_net_init;
dev->priv = scc;
scc->dev = dev;
spin_lock_init(&scc->lock);
if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0) {
kfree(dev);
return -EIO;
}
SET_MODULE_OWNER(dev);
err = register_netdev(dev);
if (err) {
printk(KERN_ERR "%s: can't register network device (%d)\n",
name, err);
free_netdev(dev);
scc->dev = NULL;
return err;
}
return 0;
}
......@@ -1556,8 +1551,9 @@ static unsigned char ax25_nocall[AX25_ADDR_LEN] =
/* ----> Initialize device <----- */
static int scc_net_init(struct net_device *dev)
static void scc_net_setup(struct net_device *dev)
{
SET_MODULE_OWNER(dev);
dev->tx_queue_len = 16; /* should be enough... */
dev->open = scc_net_open;
......@@ -1581,7 +1577,6 @@ static int scc_net_init(struct net_device *dev)
dev->mtu = AX25_DEF_PACLEN;
dev->addr_len = AX25_ADDR_LEN;
return 0;
}
/* ----> open network device <---- */
......@@ -1719,10 +1714,10 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct scc_mem_config memcfg;
struct scc_hw_config hwcfg;
struct scc_calibrate cal;
struct scc_channel *scc;
int chan;
unsigned char device_name[10];
unsigned char device_name[IFNAMSIZ];
void *arg;
struct scc_channel *scc;
scc = (struct scc_channel *) dev->priv;
arg = (void *) ifr->ifr_data;
......@@ -1828,8 +1823,10 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");
request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");
if (Nchips+chan != 0)
scc_net_setup(&SCC_Info[2*Nchips+chan], device_name, 1);
if (Nchips+chan != 0 &&
scc_net_alloc(device_name,
&SCC_Info[2*Nchips+chan]))
return -EINVAL;
}
}
......@@ -1978,39 +1975,58 @@ static struct net_device_stats *scc_net_get_stats(struct net_device *dev)
/* * dump statistics to /proc/net/z8530drv * */
/* ******************************************************************** */
#ifdef CONFIG_PROC_FS
static int scc_net_get_info(char *buffer, char **start, off_t offset, int length)
static inline struct scc_channel *scc_net_seq_idx(loff_t pos)
{
struct scc_channel *scc;
struct scc_kiss *kiss;
struct scc_stat *stat;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int k;
len += sprintf(buffer, "z8530drv-"VERSION"\n");
if (!Driver_Initialized)
{
len += sprintf(buffer+len, "not initialized\n");
goto done;
for (k = 0; k < Nchips*2; ++k) {
if (!SCC_Info[k].init)
continue;
if (pos-- == 0)
return &SCC_Info[k];
}
return NULL;
}
if (!Nchips)
{
len += sprintf(buffer+len, "chips missing\n");
goto done;
static void *scc_net_seq_start(struct seq_file *seq, loff_t *pos)
{
return *pos ? scc_net_seq_idx(*pos - 1) : SEQ_START_TOKEN;
}
static void *scc_net_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
unsigned k;
struct scc_channel *scc = v;
++*pos;
for (k = (v == SEQ_START_TOKEN) ? 0 : (scc - SCC_Info)+1;
k < Nchips*2; ++k) {
if (SCC_Info[k].init)
return &SCC_Info[k];
}
return NULL;
}
for (k = 0; k < Nchips*2; k++)
{
scc = &SCC_Info[k];
stat = &scc->stat;
kiss = &scc->kiss;
static void scc_net_seq_stop(struct seq_file *seq, void *v)
{
}
static int scc_net_seq_show(struct seq_file *seq, void *v)
{
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "z8530drv-"VERSION"\n");
} else if (!Driver_Initialized) {
seq_puts(seq, "not initialized\n");
} else if (!Nchips) {
seq_puts(seq, "chips missing\n");
} else {
const struct scc_channel *scc = v;
const struct scc_stat *stat = &scc->stat;
const struct scc_kiss *kiss = &scc->kiss;
if (!scc->init)
continue;
/* dev data ctrl irq clock brand enh vector special option
* baud nrz clocksrc softdcd bufsize
......@@ -2021,24 +2037,24 @@ static int scc_net_get_info(char *buffer, char **start, off_t offset, int length
* R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ##
*/
len += sprintf(buffer+len, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n",
seq_printf(seq, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n",
scc->dev->name,
scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand,
scc->enhanced, Vector_Latch, scc->special,
scc->option);
len += sprintf(buffer+len, "\t%lu %d %d %d %d\n",
seq_printf(seq, "\t%lu %d %d %d %d\n",
scc->modem.speed, scc->modem.nrz,
scc->modem.clocksrc, kiss->softdcd,
stat->bufsize);
len += sprintf(buffer+len, "\t%lu %lu %lu %lu\n",
seq_printf(seq, "\t%lu %lu %lu %lu\n",
stat->rxints, stat->txints, stat->exints, stat->spints);
len += sprintf(buffer+len, "\t%lu %lu %d / %lu %lu %d / %d %d\n",
seq_printf(seq, "\t%lu %lu %d / %lu %lu %d / %d %d\n",
stat->rxframes, stat->rxerrs, stat->rx_over,
stat->txframes, stat->txerrs, stat->tx_under,
stat->nospace, stat->tx_state);
#define K(x) kiss->x
len += sprintf(buffer+len, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n",
seq_printf(seq, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n",
K(txdelay), K(persist), K(slottime), K(tailtime),
K(fulldup), K(waittime), K(mintime), K(maxkeyup),
K(idletime), K(maxdefer), K(tx_inhibit), K(group));
......@@ -2047,43 +2063,49 @@ static int scc_net_get_info(char *buffer, char **start, off_t offset, int length
{
int reg;
len += sprintf(buffer+len, "\tW ");
seq_printf(seq, "\tW ");
for (reg = 0; reg < 16; reg++)
len += sprintf(buffer+len, "%2.2x ", scc->wreg[reg]);
len += sprintf(buffer+len, "\n");
seq_printf(seq, "%2.2x ", scc->wreg[reg]);
seq_printf(seq, "\n");
len += sprintf(buffer+len, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1));
seq_printf(seq, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1));
for (reg = 3; reg < 8; reg++)
len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg));
len += sprintf(buffer+len, "XX ");
seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg));
seq_printf(seq, "XX ");
for (reg = 9; reg < 16; reg++)
len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg));
len += sprintf(buffer+len, "\n");
seq_printf(seq, "%2.2x ", InReg(scc->ctrl, reg));
seq_printf(seq, "\n");
}
#endif
len += sprintf(buffer+len, "\n");
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
break;
seq_putc(seq, '\n');
}
done:
return 0;
}
*start = buffer + (offset - begin);
len -= (offset - begin);
static struct seq_operations scc_net_seq_ops = {
.start = scc_net_seq_start,
.next = scc_net_seq_next,
.stop = scc_net_seq_stop,
.show = scc_net_seq_show,
};
if (len > length) len = length;
return len;
static int scc_net_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &scc_net_seq_ops);
}
static struct file_operations scc_net_seq_fops = {
.owner = THIS_MODULE,
.open = scc_net_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#endif /* CONFIG_PROC_FS */
/* ******************************************************************** */
/* * Init SCC driver * */
......@@ -2091,23 +2113,18 @@ static int scc_net_get_info(char *buffer, char **start, off_t offset, int length
static int __init scc_init_driver (void)
{
int result;
char devname[10];
char devname[IFNAMSIZ];
printk(banner);
spin_lock_init(&iolock);
sprintf(devname,"%s0", SCC_DriverName);
result = scc_net_setup(SCC_Info, devname, 0);
if (result)
{
if (scc_net_alloc(devname, SCC_Info)) {
printk(KERN_ERR "z8530drv: cannot initialize module\n");
return result;
return -EIO;
}
proc_net_create("z8530drv", 0, scc_net_get_info);
proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops);
return 0;
}
......@@ -2117,11 +2134,12 @@ static void __exit scc_cleanup_driver(void)
io_port ctrl;
int k;
struct scc_channel *scc;
struct net_device *dev;
if (Nchips == 0)
if (Nchips == 0 && (dev = SCC_Info[0].dev))
{
unregister_netdev(SCC_Info[0].dev);
free_netdev(SCC_Info[0].dev);
unregister_netdev(dev);
free_netdev(dev);
}
/* Guard against chip prattle */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment