Commit c59bba75 authored by Duncan Sands's avatar Duncan Sands Committed by Greg Kroah-Hartman

[PATCH] USB ATM: new usbatm core

Rework the core usbatm code: minidrivers (i.e. drivers for particular
modems) now register themselves with the usbatm core, supplying methods
for binding/unbinding etc.  The design was inspired by usb-serial and
usbnet.  At the same time, more common code from the speedtch and
cxacru (patch 3/5) drivers was generalized and moved into the core.  The
transmission and reception parts have been unified and simplified.  Since
this is a major change and I don't like underscores in file names,
usb_atm.[ch] has been renamed usbatm.[ch].

Many thanks to Roman Kagan, who did a lot of the coding.
Signed-off-by: default avatarDuncan Sands <baldrick@free.fr>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d49d4317
/****************************************************************************** /******************************************************************************
* usb_atm.h - Generic USB xDSL driver core * usbatm.h - Generic USB xDSL driver core
* *
* Copyright (C) 2001, Alcatel * Copyright (C) 2001, Alcatel
* Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
...@@ -21,12 +21,10 @@ ...@@ -21,12 +21,10 @@
* *
******************************************************************************/ ******************************************************************************/
#ifndef _USBATM_H_
#define _USBATM_H_
#include <linux/config.h> #include <linux/config.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <asm/semaphore.h>
/* /*
#define DEBUG #define DEBUG
...@@ -37,140 +35,149 @@ ...@@ -37,140 +35,149 @@
# define DEBUG # define DEBUG
#endif #endif
#include <asm/semaphore.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/stringify.h>
#include <linux/usb.h> #include <linux/usb.h>
#ifdef DEBUG #ifdef DEBUG
#define UDSL_ASSERT(x) BUG_ON(!(x)) #define UDSL_ASSERT(x) BUG_ON(!(x))
#else #else
#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '" #x "' at line %d", __LINE__); } while(0) #define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0)
#endif #endif
#define UDSL_MAX_RCV_URBS 4 #define usb_err(instance, format, arg...) \
#define UDSL_MAX_SND_URBS 4 dev_err(&(instance)->usb_intf->dev , format , ## arg)
#define UDSL_MAX_RCV_BUFS 8 #define usb_info(instance, format, arg...) \
#define UDSL_MAX_SND_BUFS 8 dev_info(&(instance)->usb_intf->dev , format , ## arg)
#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */ #define usb_warn(instance, format, arg...) \
#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */ dev_warn(&(instance)->usb_intf->dev , format , ## arg)
#define UDSL_DEFAULT_RCV_URBS 2 #define usb_dbg(instance, format, arg...) \
#define UDSL_DEFAULT_SND_URBS 2 dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
#define UDSL_DEFAULT_RCV_BUFS 4
#define UDSL_DEFAULT_SND_BUFS 4 /* FIXME: move to dev_* once ATM is driver model aware */
#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */ #define atm_printk(level, instance, format, arg...) \
#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */ printk(level "ATM dev %d: " format , (instance)->atm_dev->number, ## arg)
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) #define atm_err(instance, format, arg...) \
#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD) atm_printk(KERN_ERR, instance , format , ## arg)
#define atm_info(instance, format, arg...) \
/* receive */ atm_printk(KERN_INFO, instance , format , ## arg)
#define atm_warn(instance, format, arg...) \
struct udsl_receive_buffer { atm_printk(KERN_WARNING, instance , format , ## arg)
struct list_head list; #ifdef DEBUG
unsigned char *base; #define atm_dbg(instance, format, arg...) \
unsigned int filled_cells; atm_printk(KERN_DEBUG, instance , format , ## arg)
}; #else
#define atm_dbg(instance, format, arg...) \
do {} while (0)
#endif
struct udsl_receiver {
struct list_head list;
struct udsl_receive_buffer *buffer;
struct urb *urb;
struct udsl_instance_data *instance;
};
struct udsl_vcc_data { /* mini driver */
/* vpi/vci lookup */
struct list_head list;
short vpi;
int vci;
struct atm_vcc *vcc;
/* raw cell reassembly */ struct usbatm_data;
struct sk_buff *sarb;
};
/* send */ /*
* Assuming all methods exist and succeed, they are called in this order:
*
* bind, heavy_init, atm_start, ..., atm_stop, unbind
*/
struct udsl_send_buffer { struct usbatm_driver {
struct list_head list; struct module *owner;
unsigned char *base;
unsigned char *free_start;
unsigned int free_cells;
};
struct udsl_sender { const char *driver_name;
struct list_head list;
struct udsl_send_buffer *buffer; /*
struct urb *urb; * init device ... can sleep, or cause probe() failure. Drivers with a heavy_init
struct udsl_instance_data *instance; * method can avoid having it called by setting need_heavy_init to zero.
}; */
int (*bind) (struct usbatm_data *, struct usb_interface *,
const struct usb_device_id *id, int *need_heavy_init);
/* additional device initialization that is too slow to be done in probe() */
int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
/* cleanup device ... can sleep, but can't fail */
void (*unbind) (struct usbatm_data *, struct usb_interface *);
struct udsl_control { /* init ATM device ... can sleep, or cause ATM initialization failure */
struct atm_skb_data atm_data; int (*atm_start) (struct usbatm_data *, struct atm_dev *);
unsigned int num_cells;
unsigned int num_entire; /* cleanup ATM device ... can sleep, but can't fail */
unsigned int pdu_padding; void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
unsigned char aal5_trailer[ATM_AAL5_TRAILER];
int in; /* rx endpoint */
int out; /* tx endpoint */
unsigned rx_padding;
unsigned tx_padding;
}; };
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb) extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
struct usbatm_driver *driver);
extern void usbatm_usb_disconnect(struct usb_interface *intf);
/* main driver data */
enum udsl_status { struct usbatm_channel {
UDSL_NO_FIRMWARE, int endpoint; /* usb pipe */
UDSL_LOADING_FIRMWARE, unsigned int stride; /* ATM cell size + padding */
UDSL_LOADED_FIRMWARE unsigned int buf_size; /* urb buffer size */
spinlock_t lock;
struct list_head list;
struct tasklet_struct tasklet;
struct timer_list delay;
struct usbatm_data *usbatm;
}; };
struct udsl_instance_data { /* main driver data */
struct kref refcount;
struct semaphore serialize; struct usbatm_data {
/******************
* public fields *
******************/
/* USB device part */ /* mini driver */
struct usbatm_driver *driver;
void *driver_data;
char driver_name[16];
/* USB device */
struct usb_device *usb_dev; struct usb_device *usb_dev;
struct usb_interface *usb_intf;
char description[64]; char description[64];
int data_endpoint;
int snd_padding;
int rcv_padding;
const char *driver_name;
/* ATM device part */ /* ATM device */
struct atm_dev *atm_dev; struct atm_dev *atm_dev;
struct list_head vcc_list;
/* firmware */ /********************************
int (*firmware_wait) (struct udsl_instance_data *); * private fields - do not use *
enum udsl_status status; ********************************/
wait_queue_head_t firmware_waiters;
/* receive */ struct kref refcount;
struct udsl_receiver receivers[UDSL_MAX_RCV_URBS]; struct semaphore serialize;
struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
spinlock_t receive_lock; /* heavy init */
struct list_head spare_receivers; int thread_pid;
struct list_head filled_receive_buffers; struct completion thread_started;
struct completion thread_exited;
struct tasklet_struct receive_tasklet; /* ATM device */
struct list_head spare_receive_buffers; struct list_head vcc_list;
/* send */ struct usbatm_channel rx_channel;
struct udsl_sender senders[UDSL_MAX_SND_URBS]; struct usbatm_channel tx_channel;
struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
struct sk_buff_head sndqueue; struct sk_buff_head sndqueue;
spinlock_t send_lock;
struct list_head spare_senders;
struct list_head spare_send_buffers;
struct tasklet_struct send_tasklet;
struct sk_buff *current_skb; /* being emptied */ struct sk_buff *current_skb; /* being emptied */
struct udsl_send_buffer *current_buffer; /* being filled */
struct list_head filled_send_buffers; struct urb *urbs[0];
}; };
extern int udsl_instance_setup(struct usb_device *dev, #endif /* _USBATM_H_ */
struct udsl_instance_data *instance);
extern void udsl_instance_disconnect(struct udsl_instance_data *instance);
extern void udsl_get_instance(struct udsl_instance_data *instance);
extern void udsl_put_instance(struct udsl_instance_data *instance);
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