drivers/tty/ipwireless/network.c

Source file repositories/reference/linux-study-clean/drivers/tty/ipwireless/network.c

File Facts

System
Linux kernel
Corpus path
drivers/tty/ipwireless/network.c
Extension
.c
Size
12887 bytes
Lines
518
Domain
Driver Families
Bucket
drivers/tty
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ipw_network {
	/* Hardware context, used for calls to hardware layer. */
	struct ipw_hardware *hardware;
	/* Context for kernel 'generic_ppp' functionality */
	struct ppp_channel *ppp_channel;
	/* tty context connected with IPW console */
	struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS];
	/* True if ppp needs waking up once we're ready to xmit */
	int ppp_blocked;
	/* Number of packets queued up in hardware module. */
	int outgoing_packets_queued;
	/* Spinlock to avoid interrupts during shutdown */
	spinlock_t lock;
	struct mutex close_lock;

	/* PPP ioctl data, not actually used anywere */
	unsigned int flags;
	unsigned int rbits;
	u32 xaccm[8];
	u32 raccm;
	int mru;

	int shutting_down;
	unsigned int ras_control_lines;

	struct work_struct work_go_online;
	struct work_struct work_go_offline;
};

static void notify_packet_sent(void *callback_data, unsigned int packet_length)
{
	struct ipw_network *network = callback_data;
	unsigned long flags;

	spin_lock_irqsave(&network->lock, flags);
	network->outgoing_packets_queued--;
	if (network->ppp_channel != NULL) {
		if (network->ppp_blocked) {
			network->ppp_blocked = 0;
			spin_unlock_irqrestore(&network->lock, flags);
			ppp_output_wakeup(network->ppp_channel);
			if (ipwireless_debug)
				printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
				       ": ppp unblocked\n");
		} else
			spin_unlock_irqrestore(&network->lock, flags);
	} else
		spin_unlock_irqrestore(&network->lock, flags);
}

/*
 * Called by the ppp system when it has a packet to send to the hardware.
 */
static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
				     struct sk_buff *skb)
{
	struct ipw_network *network = ppp_channel->private;
	unsigned long flags;

	spin_lock_irqsave(&network->lock, flags);
	if (network->outgoing_packets_queued < ipwireless_out_queue) {
		unsigned char *buf;
		static unsigned char header[] = {
			PPP_ALLSTATIONS, /* 0xff */
			PPP_UI,		 /* 0x03 */
		};
		int ret;

		network->outgoing_packets_queued++;
		spin_unlock_irqrestore(&network->lock, flags);

		/*
		 * If we have the requested amount of headroom in the skb we
		 * were handed, then we can add the header efficiently.
		 */
		if (skb_headroom(skb) >= 2) {
			memcpy(skb_push(skb, 2), header, 2);
			ret = ipwireless_send_packet(network->hardware,
					       IPW_CHANNEL_RAS, skb->data,
					       skb->len,
					       notify_packet_sent,
					       network);
			if (ret < 0) {
				skb_pull(skb, 2);
				return 0;
			}
		} else {
			/* Otherwise (rarely) we do it inefficiently. */
			buf = kmalloc(skb->len + 2, GFP_ATOMIC);
			if (!buf)

Annotation

Implementation Notes