/* iBurst (TM) compatible driver for Linux kernel 2.6
 * based on the original ArrayComm (TM) iBurst (TM) driver.
 * Nicholas Jefferson <xanthophile@gmail.com>
 * 11 May 2005
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/netdevice.h>

/**
 * enum ib_net_status - network device status.
 */
enum ib_net_status
{
	STATUS_READY = 0x02,
};

/**
 * struct ib_net_driver_t - driver callback functions.
 * @name: driver name.
 * @poll: called by ib_net_poll, ib_net_tx_start.
 * @stop: called by ib_net_stop.
 * @tx_timeout: called by ib_net_tx_timeout.
 */
struct ib_net_driver_t {
	char *name;
	void (*poll)(void*);
	void (*stop)(void*);
	void (*tx_timeout)(void*);
};

/**
 * struct ib_net_cell_t - cell header.
 * @word: packet length and flags.
 *     word[0].2 word[0].1 word[0].0 word[1]: packet length.
 *     word[0].3: broadcast flag.
 *     word[0].6 word[0].5 word[0].4: priority field (ignore this field).
 *     word[0].7: extension flag (drop packet if set).
 * @status: packet count.
 * @check: ones' complement of word[1].
 * @proto: next protocol.
 * @data: payload.
 */
struct ib_net_cell_t {
	u_char word[2];
	u_char status;
	u_char check;
	u_char proto[2];
	u_char data[0];
};

#define IB_NET_CELL_HDR sizeof(struct ib_net_cell_t)
#define IB_NET_CELL_SIZE ((IB_NET_CELL_HDR + ETH_DATA_LEN + 31) & ~31)

/**
 * struct ib_net_packet_t - standard ethernet header.
 * @dest: destination MAC address.
 * @source: source MAC address.
 * @proto: next protocol.
 * @data: payload.
 */
struct ib_net_packet_t {
	u_char dest[ETH_ALEN];
	u_char source[ETH_ALEN];
	u_char proto[2];
	u_char data[0];
};

#define IB_NET_PACKET_HDR sizeof(struct ib_net_packet_t)

/**
 * struct ib_net_modem_t - modem state.
 * @dev: network device.
 * @stats: device statistics.
 * @status: network device status; used by ib_net_stop.
 * @driver: driver callback functions.
 * @instance: instance for callback functions.
 * @rx_buf: buffer to receive one iBurst ethernet cell.
 * @tx_buf: buffer to transmit one iBurst ethernet cell.
 * @rx_status:
 * @tx_throttle: throttle flag.
 * @tx_queue: transmit cell queue.
 * @task_queue: bottom half handler.
 */
struct ib_net_modem_t {
	struct net_device dev;
	struct net_device_stats stats;
	enum ib_net_status status;
	struct ib_net_driver_t *driver;
	void *instance;
	u_char rx_buf[IB_NET_CELL_SIZE];
	u_char tx_buf[IB_NET_CELL_SIZE];
	u_char rx_status;
	int tx_throttle;
	struct sk_buff_head tx_queue;
	struct work_struct work_queue;
};

/**
 * ib_net_addr - set network device MAC address.
 * @modem: modem state.
 * @addr: MAC address.
 */
static inline void ib_net_addr(struct ib_net_modem_t *modem, u_char *addr)
{
	int i;

	memcpy(modem->dev.dev_addr, addr, ETH_ALEN);
	modem->dev.dev_addr[ETH_ALEN-1] ^= 1; 
	printk(KERN_DEBUG "ib-net: addr %02X", *modem->dev.dev_addr);
	for (i = 1; i < ETH_ALEN; i += 1)
		printk(":%02X", modem->dev.dev_addr[i]);
	printk("\n");
}

/**
 * ib_net_attach - attach network device.
 * @modem: modem state.
 */
static inline void ib_net_attach(struct ib_net_modem_t *modem)
{
	netif_device_attach(&modem->dev);
}

/**
 * ib_net_detach - detach network device.
 * @modem: modem state.
 */
static inline void ib_net_detach(struct ib_net_modem_t *modem)
{
	netif_device_detach(&modem->dev);
}

/**
 * ib_net_stop - stop transmitting processes.
 * @modem: modem state.
 */
static inline void ib_net_stop(struct ib_net_modem_t *modem)
{
	netif_stop_queue(&modem->dev);
}

/**
 * ib_net_wake - wake transmitting processes.
 * @modem: modem state.
 */
static inline void ib_net_wake(struct ib_net_modem_t *modem)
{
	if (modem->tx_throttle == 0)
		netif_wake_queue(&modem->dev);
}

/**
 * ib_net_schedule - schedule bottom half handler.
 * @modem: modem state.
 */
static inline void ib_net_schedule(struct ib_net_modem_t *modem)
{
	schedule_work(&modem->work_queue);
}

extern void ib_net_parse(struct ib_net_modem_t *modem, int nbuf);
extern int ib_net_fill(struct ib_net_modem_t *modem);
extern void ib_net_deregister(struct ib_net_modem_t *modem);
extern struct ib_net_modem_t *ib_net_register(u_char *name);
