Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+1231 −0

File changed and moved.

Preview size limit exceeded, changes collapsed.

+183 −0
Original line number Diff line number Diff line
/******************************************************************************
 *  usb_atm.h - Generic USB xDSL driver core
 *  usbatm.h - Generic USB xDSL driver core
 *
 *  Copyright (C) 2001, Alcatel
 *  Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
@@ -21,12 +21,10 @@
 *
 ******************************************************************************/

#ifndef	_USBATM_H_
#define	_USBATM_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
@@ -37,140 +35,149 @@
#	define DEBUG
#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>

#ifdef DEBUG
#define UDSL_ASSERT(x)	BUG_ON(!(x))
#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

#define UDSL_MAX_RCV_URBS		4
#define UDSL_MAX_SND_URBS		4
#define UDSL_MAX_RCV_BUFS		8
#define UDSL_MAX_SND_BUFS		8
#define UDSL_MAX_RCV_BUF_SIZE		1024	/* ATM cells */
#define UDSL_MAX_SND_BUF_SIZE		1024	/* ATM cells */
#define UDSL_DEFAULT_RCV_URBS		2
#define UDSL_DEFAULT_SND_URBS		2
#define UDSL_DEFAULT_RCV_BUFS		4
#define UDSL_DEFAULT_SND_BUFS		4
#define UDSL_DEFAULT_RCV_BUF_SIZE	64	/* ATM cells */
#define UDSL_DEFAULT_SND_BUF_SIZE	64	/* ATM cells */

#define ATM_CELL_HEADER			(ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
#define UDSL_NUM_CELLS(x)		(((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)

/* receive */

struct udsl_receive_buffer {
	struct list_head list;
	unsigned char *base;
	unsigned int filled_cells;
};
#define usb_err(instance, format, arg...)	\
	dev_err(&(instance)->usb_intf->dev , format , ## arg)
#define usb_info(instance, format, arg...)	\
	dev_info(&(instance)->usb_intf->dev , format , ## arg)
#define usb_warn(instance, format, arg...)	\
	dev_warn(&(instance)->usb_intf->dev , format , ## arg)
#define usb_dbg(instance, format, arg...)	\
	dev_dbg(&(instance)->usb_intf->dev , format , ## arg)

/* FIXME: move to dev_* once ATM is driver model aware */
#define atm_printk(level, instance, format, arg...)	\
	printk(level "ATM dev %d: " format , (instance)->atm_dev->number, ## arg)

#define atm_err(instance, format, arg...)	\
	atm_printk(KERN_ERR, instance , format , ## arg)
#define atm_info(instance, format, arg...)	\
	atm_printk(KERN_INFO, instance , format , ## arg)
#define atm_warn(instance, format, arg...)	\
	atm_printk(KERN_WARNING, instance , format , ## arg)
#ifdef DEBUG
#define atm_dbg(instance, format, arg...)	\
	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 {
	/* vpi/vci lookup */
	struct list_head list;
	short vpi;
	int vci;
	struct atm_vcc *vcc;
/* mini driver */

	/* raw cell reassembly */
	struct sk_buff *sarb;
};
struct usbatm_data;

/* 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 list_head list;
	unsigned char *base;
	unsigned char *free_start;
	unsigned int free_cells;
};
struct usbatm_driver {
	struct module *owner;

struct udsl_sender {
	struct list_head list;
	struct udsl_send_buffer *buffer;
	struct urb *urb;
	struct udsl_instance_data *instance;
};
	const char *driver_name;

	/*
	*  init device ... can sleep, or cause probe() failure.  Drivers with a heavy_init
	*  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 {
	struct atm_skb_data atm_data;
	unsigned int num_cells;
	unsigned int num_entire;
	unsigned int pdu_padding;
	unsigned char aal5_trailer[ATM_AAL5_TRAILER];
	/* init ATM device ... can sleep, or cause ATM initialization failure */
	int (*atm_start) (struct usbatm_data *, struct atm_dev *);

	/* cleanup ATM device ... can sleep, but can't fail */
	void (*atm_stop) (struct usbatm_data *, struct atm_dev *);

        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 {
	UDSL_NO_FIRMWARE,
	UDSL_LOADING_FIRMWARE,
	UDSL_LOADED_FIRMWARE
struct usbatm_channel {
	int endpoint;			/* usb pipe */
	unsigned int stride;		/* ATM cell size + padding */
	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 {
	struct kref refcount;
	struct semaphore serialize;
/* main driver data */

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_interface *usb_intf;
	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 list_head vcc_list;

	/* firmware */
	int (*firmware_wait) (struct udsl_instance_data *);
	enum udsl_status status;
	wait_queue_head_t firmware_waiters;
	/********************************
	*  private fields - do not use  *
        ********************************/

	/* receive */
	struct udsl_receiver receivers[UDSL_MAX_RCV_URBS];
	struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
	struct kref refcount;
	struct semaphore serialize;

	spinlock_t receive_lock;
	struct list_head spare_receivers;
	struct list_head filled_receive_buffers;
	/* heavy init */
	int thread_pid;
	struct completion thread_started;
	struct completion thread_exited;

	struct tasklet_struct receive_tasklet;
	struct list_head spare_receive_buffers;
	/* ATM device */
	struct list_head vcc_list;

	/* send */
	struct udsl_sender senders[UDSL_MAX_SND_URBS];
	struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
	struct usbatm_channel rx_channel;
	struct usbatm_channel tx_channel;

	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 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,
			       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);
#endif	/* _USBATM_H_ */