*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
+#include <linux/moduleparam.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
/* -------- driver information -------------------------------------- */
-static struct class_simple *capi_class;
+static struct class *capi_class;
-int capi_major = 68; /* allocated */
+static int capi_major = 68; /* allocated */
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
#define CAPINC_NR_PORTS 32
#define CAPINC_MAX_PORTS 256
-int capi_ttymajor = 191;
-int capi_ttyminors = CAPINC_NR_PORTS;
+static int capi_ttymajor = 191;
+static int capi_ttyminors = CAPINC_NR_PORTS;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-MODULE_PARM(capi_major, "i");
+module_param_named(major, capi_major, uint, 0);
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-MODULE_PARM(capi_ttymajor, "i");
-MODULE_PARM(capi_ttyminors, "i");
+module_param_named(ttymajor, capi_ttymajor, uint, 0);
+module_param_named(ttyminors, capi_ttyminors, uint, 0);
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
/* -------- defines ------------------------------------------------- */
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct capiminor;
+struct datahandle_queue {
+ struct list_head list;
+ u16 datahandle;
+};
+
struct capiminor {
struct list_head list;
struct capincci *nccip;
int outbytes;
/* transmit path */
- struct datahandle_queue {
- struct datahandle_queue *next;
- u16 datahandle;
- } *ackqueue;
+ struct list_head ackqueue;
int nack;
-
+ spinlock_t ackqlock;
};
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
/* -------- global variables ---------------------------------------- */
-static rwlock_t capidev_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(capidev_list_lock);
static LIST_HEAD(capidev_list);
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static rwlock_t capiminor_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(capiminor_list_lock);
static LIST_HEAD(capiminor_list);
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
{
- struct datahandle_queue *n, **pp;
+ struct datahandle_queue *n;
+ unsigned long flags;
n = kmalloc(sizeof(*n), GFP_ATOMIC);
- if (!n) {
- printk(KERN_ERR "capi: alloc datahandle failed\n");
- return -1;
+ if (unlikely(!n)) {
+ printk(KERN_ERR "capi: alloc datahandle failed\n");
+ return -1;
}
- n->next = NULL;
n->datahandle = datahandle;
- for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
- *pp = n;
+ INIT_LIST_HEAD(&n->list);
+ spin_lock_irqsave(&mp->ackqlock, flags);
+ list_add_tail(&n->list, &mp->ackqueue);
mp->nack++;
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
return 0;
}
static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
{
- struct datahandle_queue **pp, *p;
+ struct datahandle_queue *p, *tmp;
+ unsigned long flags;
- for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
- if ((*pp)->datahandle == datahandle) {
- p = *pp;
- *pp = (*pp)->next;
+ spin_lock_irqsave(&mp->ackqlock, flags);
+ list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+ if (p->datahandle == datahandle) {
+ list_del(&p->list);
kfree(p);
mp->nack--;
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
return 0;
}
}
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
return -1;
}
static void capiminor_del_all_ack(struct capiminor *mp)
{
- struct datahandle_queue **pp, *p;
+ struct datahandle_queue *p, *tmp;
+ unsigned long flags;
- pp = &mp->ackqueue;
- while (*pp) {
- p = *pp;
- *pp = (*pp)->next;
+ spin_lock_irqsave(&mp->ackqlock, flags);
+ list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+ list_del(&p->list);
kfree(p);
mp->nack--;
}
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
}
unsigned int minor = 0;
unsigned long flags;
- mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
+ mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
if (!mp) {
printk(KERN_ERR "capi: can't alloc capiminor\n");
return NULL;
}
- memset(mp, 0, sizeof(struct capiminor));
mp->ap = ap;
mp->ncci = ncci;
mp->msgid = 0;
atomic_set(&mp->ttyopencount,0);
+ INIT_LIST_HEAD(&mp->ackqueue);
+ spin_lock_init(&mp->ackqlock);
skb_queue_head_init(&mp->inqueue);
skb_queue_head_init(&mp->outqueue);
kfree(mp);
}
-struct capiminor *capiminor_find(unsigned int minor)
+static struct capiminor *capiminor_find(unsigned int minor)
{
struct list_head *l;
struct capiminor *p = NULL;
struct capiminor *mp = NULL;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- np = kmalloc(sizeof(*np), GFP_ATOMIC);
+ np = kzalloc(sizeof(*np), GFP_ATOMIC);
if (!np)
return NULL;
- memset(np, 0, sizeof(struct capincci));
np->ncci = ncci;
np->cdev = cdev;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct capidev *cdev;
unsigned long flags;
- cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return NULL;
- memset(cdev, 0, sizeof(struct capidev));
init_MUTEX(&cdev->ncci_list_sem);
skb_queue_head_init(&cdev->recvqueue);
struct sk_buff *nskb;
int datalen;
u16 errcode, datahandle;
-
+ struct tty_ldisc *ld;
+
datalen = skb->len - CAPIMSG_LEN(skb->data);
- if (mp->tty) {
- if (mp->tty->ldisc.receive_buf == 0) {
- printk(KERN_ERR "capi: ldisc has no receive_buf function\n");
- return -1;
- }
- if (mp->ttyinstop) {
+ if (mp->tty == NULL)
+ {
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: currently no receiver\n");
+#endif
+ return -1;
+ }
+
+ ld = tty_ldisc_ref(mp->tty);
+ if (ld == NULL)
+ return -1;
+ if (ld->receive_buf == NULL) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
- printk(KERN_DEBUG "capi: recv tty throttled\n");
+ printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
#endif
- return -1;
- }
- if (mp->tty->ldisc.receive_room &&
- mp->tty->ldisc.receive_room(mp->tty) < datalen) {
+ goto bad;
+ }
+ if (mp->ttyinstop) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
- printk(KERN_DEBUG "capi: no room in tty\n");
+ printk(KERN_DEBUG "capi: recv tty throttled\n");
#endif
- return -1;
- }
- if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
- printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
- return -1;
- }
- datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
- errcode = capi20_put_message(mp->ap, nskb);
- if (errcode != CAPI_NOERROR) {
- printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
- errcode);
- kfree_skb(nskb);
- return -1;
- }
- (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
- datahandle, skb->len);
+ goto bad;
+ }
+ if (mp->tty->receive_room < datalen) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: no room in tty\n");
#endif
- mp->tty->ldisc.receive_buf(mp->tty, skb->data, NULL, skb->len);
- kfree_skb(skb);
- return 0;
-
+ goto bad;
+ }
+ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+ printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+ goto bad;
}
+ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+ errcode = capi20_put_message(mp->ap, nskb);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+ errcode);
+ kfree_skb(nskb);
+ goto bad;
+ }
+ (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: currently no receiver\n");
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
+ datahandle, skb->len);
#endif
+ ld->receive_buf(mp->tty, skb->data, NULL, skb->len);
+ kfree_skb(skb);
+ tty_ldisc_deref(ld);
+ return 0;
+bad:
+ tty_ldisc_deref(ld);
return -1;
}
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+
datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
#ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
#endif
kfree_skb(skb);
(void)capiminor_del_ack(mp, datahandle);
- if (mp->tty) {
- if (mp->tty->ldisc.write_wakeup)
- mp->tty->ldisc.write_wakeup(mp->tty);
- }
+ if (mp->tty)
+ tty_wakeup(mp->tty);
(void)handle_minor_send(mp);
} else {
struct sk_buff *skb;
size_t copied;
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (!cdev->ap.applid)
return -ENODEV;
struct sk_buff *skb;
u16 mlen;
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (!cdev->ap.applid)
return -ENODEV;
if ((file->private_data = capidev_alloc()) == 0)
return -ENOMEM;
- return 0;
+ return nonseekable_open(inode, file);
}
static int
{
struct capiminor *mp;
- if ((mp = capiminor_find(iminor(file->f_dentry->d_inode))) == 0)
+ if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
return -ENXIO;
if (mp->nccip == 0)
return -ENXIO;
#endif
}
-static int capinc_tty_write(struct tty_struct * tty, int from_user,
+static int capinc_tty_write(struct tty_struct * tty,
const unsigned char *buf, int count)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
- int retval;
#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n",
- from_user, count);
+ printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
#endif
if (!mp || !mp->nccip) {
}
skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
- if (from_user) {
- retval = copy_from_user(skb_put(skb, count), buf, count);
- if (retval) {
- kfree_skb(skb);
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval);
-#endif
- return -EFAULT;
- }
- } else {
- memcpy(skb_put(skb, count), buf, count);
- }
+ memcpy(skb_put(skb, count), buf, count);
skb_queue_tail(&mp->outqueue, skb);
mp->outbytes += skb->len;
return room;
}
-int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
if (!mp || !mp->nccip) {
return error;
}
-static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
{
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_set_termios\n");
static struct tty_driver *capinc_tty_driver;
-static struct tty_operations capinc_ops = {
+static const struct tty_operations capinc_ops = {
.open = capinc_tty_open,
.close = capinc_tty_close,
.write = capinc_tty_write,
drv->owner = THIS_MODULE;
drv->driver_name = "capi_nc";
- drv->devfs_name = "capi/";
drv->name = "capi";
drv->major = capi_ttymajor;
drv->minor_start = 0;
{
char *p;
char *compileinfo;
+ int major_ret;
if ((p = strchr(revision, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
} else
strcpy(rev, "1.0");
- if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+ major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
+ if (major_ret < 0) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
- return -EIO;
+ return major_ret;
}
-
- capi_class = class_simple_create(THIS_MODULE, "capi");
+ capi_class = class_create(THIS_MODULE, "capi");
if (IS_ERR(capi_class)) {
unregister_chrdev(capi_major, "capi20");
return PTR_ERR(capi_class);
}
- class_simple_device_add(capi_class, MKDEV(capi_major, 0), NULL, "capi");
- devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
- "isdn/capi20");
+ class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
if (capinc_tty_init() < 0) {
- class_simple_device_remove(MKDEV(capi_major, 0));
- class_simple_destroy(capi_class);
+ class_device_destroy(capi_class, MKDEV(capi_major, 0));
+ class_destroy(capi_class);
unregister_chrdev(capi_major, "capi20");
return -ENOMEM;
}
{
proc_exit();
- class_simple_device_remove(MKDEV(capi_major, 0));
- class_simple_destroy(capi_class);
+ class_device_destroy(capi_class, MKDEV(capi_major, 0));
+ class_destroy(capi_class);
unregister_chrdev(capi_major, "capi20");
- devfs_remove("isdn/capi20");
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
capinc_tty_exit();