aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/array.c
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2009-04-18 16:17:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-19 13:51:40 -0400
commitc0b7988200a82290287c6f4cd49585007f73175a (patch)
tree8e98fd4bbca599f060343936d5affb499c4aeb29 /fs/proc/array.c
parent42a17ad2762f465d291c3bc0b6ed2b3738f65481 (diff)
Revert "console ASCII glyph 1:1 mapping"
This reverts commit 1c55f18717304100a5f624c923f7cb6511b4116d. Ingo Brueckl was assuming that reverting to 1:1 mapping for chars >= 128 was not useful, but it happens to be: due to the limitations of the Linux console, when a blind user wants to read BIG5 on it, he has no other way than loading a font without SFM and let the 1:1 mapping permit the screen reader to get the BIG5 encoding. Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/array.c')
0 files changed, 0 insertions, 0 deletions
' href='#n294'>294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
/*
 * CAIF Interface registration.
 * Copyright (C) ST-Ericsson AB 2010
 * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
 * License terms: GNU General Public License (GPL) version 2
 *
 * Borrowed heavily from file: pn_dev.c. Thanks to
 *  Remi Denis-Courmont <remi.denis-courmont@nokia.com>
 *  and Sakari Ailus <sakari.ailus@nokia.com>
 */

#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__

#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <net/netns/generic.h>
#include <net/net_namespace.h>
#include <net/pkt_sched.h>
#include <net/caif/caif_device.h>
#include <net/caif/caif_dev.h>
#include <net/caif/caif_layer.h>
#include <net/caif/cfpkt.h>
#include <net/caif/cfcnfg.h>

MODULE_LICENSE("GPL");
#define TIMEOUT (HZ*5)

/* Used for local tracking of the CAIF net devices */
struct caif_device_entry {
	struct cflayer layer;
	struct list_head list;
	atomic_t in_use;
	atomic_t state;
	u16 phyid;
	struct net_device *netdev;
	wait_queue_head_t event;
};

struct caif_device_entry_list {
	struct list_head list;
	/* Protects simulanous deletes in list */
	spinlock_t lock;
};

struct caif_net {
	struct caif_device_entry_list caifdevs;
};

static int caif_net_id;
static struct cfcnfg *cfg;

static struct caif_device_entry_list *caif_device_list(struct net *net)
{
	struct caif_net *caifn;
	BUG_ON(!net);
	caifn = net_generic(net, caif_net_id);
	BUG_ON(!caifn);
	return &caifn->caifdevs;
}

/* Allocate new CAIF device. */
static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
{
	struct caif_device_entry_list *caifdevs;
	struct caif_device_entry *caifd;
	caifdevs = caif_device_list(dev_net(dev));
	BUG_ON(!caifdevs);
	caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC);
	if (!caifd)
		return NULL;
	caifd->netdev = dev;
	list_add(&caifd->list, &caifdevs->list);
	init_waitqueue_head(&caifd->event);
	return caifd;
}

static struct caif_device_entry *caif_get(struct net_device *dev)
{
	struct caif_device_entry_list *caifdevs =
	    caif_device_list(dev_net(dev));
	struct caif_device_entry *caifd;
	BUG_ON(!caifdevs);
	list_for_each_entry(caifd, &caifdevs->list, list) {
		if (caifd->netdev == dev)
			return caifd;
	}
	return NULL;
}

static void caif_device_destroy(struct net_device *dev)
{
	struct caif_device_entry_list *caifdevs =
	    caif_device_list(dev_net(dev));
	struct caif_device_entry *caifd;
	ASSERT_RTNL();
	if (dev->type != ARPHRD_CAIF)
		return;

	spin_lock_bh(&caifdevs->lock);
	caifd = caif_get(dev);
	if (caifd == NULL) {
		spin_unlock_bh(&caifdevs->lock);
		return;
	}

	list_del(&caifd->list);
	spin_unlock_bh(&caifdevs->lock);

	kfree(caifd);
}

static int transmit(struct cflayer *layer, struct cfpkt *pkt)
{
	struct caif_device_entry *caifd =
	    container_of(layer, struct caif_device_entry, layer);
	struct sk_buff *skb;

	skb = cfpkt_tonative(pkt);
	skb->dev = caifd->netdev;

	dev_queue_xmit(skb);

	return 0;
}

static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
{
	struct caif_device_entry *caifd;
	caifd = container_of(layr, struct caif_device_entry, layer);
	if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) {
		atomic_set(&caifd->in_use, 1);
		wake_up_interruptible(&caifd->event);

	} else if (ctrl == _CAIF_MODEMCMD_PHYIF_USELESS) {
		atomic_set(&caifd->in_use, 0);
		wake_up_interruptible(&caifd->event);
	}
	return 0;
}

/*
 * Stuff received packets to associated sockets.
 * On error, returns non-zero and releases the skb.
 */
static int receive(struct sk_buff *skb, struct net_device *dev,
		   struct packet_type *pkttype, struct net_device *orig_dev)
{
	struct cfpkt *pkt;
	struct caif_device_entry *caifd;
	pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
	caifd = caif_get(dev);
	if (!caifd || !caifd->layer.up || !caifd->layer.up->receive)
		return NET_RX_DROP;

	if (caifd->layer.up->receive(caifd->layer.up, pkt))
		return NET_RX_DROP;

	return 0;
}

static struct packet_type caif_packet_type __read_mostly = {
	.type = cpu_to_be16(ETH_P_CAIF),
	.func = receive,
};

static void dev_flowctrl(struct net_device *dev, int on)
{
	struct caif_device_entry *caifd = caif_get(dev);
	if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
		return;

	caifd->layer.up->ctrlcmd(caifd->layer.up,
				 on ?
				 _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND :
				 _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
				 caifd->layer.id);
}

/* notify Caif of device events */
static int caif_device_notify(struct notifier_block *me, unsigned long what,
			      void *arg)
{
	struct net_device *dev = arg;
	struct caif_device_entry *caifd = NULL;
	struct caif_dev_common *caifdev;
	enum cfcnfg_phy_preference pref;
	enum cfcnfg_phy_type phy_type;

	if (dev->type != ARPHRD_CAIF)
		return 0;

	switch (what) {
	case NETDEV_REGISTER:
		netdev_info(dev, "register\n");
		caifd = caif_device_alloc(dev);
		if (caifd == NULL)
			break;
		caifdev = netdev_priv(dev);
		caifdev->flowctrl = dev_flowctrl;
		atomic_set(&caifd->state, what);
		break;

	case NETDEV_UP:
		netdev_info(dev, "up\n");
		caifd = caif_get(dev);
		if (caifd == NULL)
			break;
		caifdev = netdev_priv(dev);
		if (atomic_read(&caifd->state) == NETDEV_UP) {
			netdev_info(dev, "already up\n");
			break;
		}
		atomic_set(&caifd->state, what);
		caifd->layer.transmit = transmit;
		caifd->layer.modemcmd = modemcmd;

		if (caifdev->use_frag)
			phy_type = CFPHYTYPE_FRAG;
		else
			phy_type = CFPHYTYPE_CAIF;

		switch (caifdev->link_select) {
		case CAIF_LINK_HIGH_BANDW:
			pref = CFPHYPREF_HIGH_BW;
			break;
		case CAIF_LINK_LOW_LATENCY:
			pref = CFPHYPREF_LOW_LAT;
			break;
		default:
			pref = CFPHYPREF_HIGH_BW;
			break;
		}
		dev_hold(dev);
		cfcnfg_add_phy_layer(cfg,
				     phy_type,
				     dev,
				     &caifd->layer,
				     &caifd->phyid,
				     pref,
				     caifdev->use_fcs,
				     caifdev->use_stx);
		strncpy(caifd->layer.name, dev->name,
			sizeof(caifd->layer.name) - 1);
		caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
		break;

	case NETDEV_GOING_DOWN:
		caifd = caif_get(dev);
		if (caifd == NULL)
			break;
		netdev_info(dev, "going down\n");

		if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN ||
			atomic_read(&caifd->state) == NETDEV_DOWN)
			break;

		atomic_set(&caifd->state, what);
		if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
			return -EINVAL;
		caifd->layer.up->ctrlcmd(caifd->layer.up,
					 _CAIF_CTRLCMD_PHYIF_DOWN_IND,
					 caifd->layer.id);
		might_sleep();
		wait_event_interruptible_timeout(caifd->event,
					atomic_read(&caifd->in_use) == 0,
					TIMEOUT);
		break;

	case NETDEV_DOWN:
		caifd = caif_get(dev);
		if (caifd == NULL)
			break;
		netdev_info(dev, "down\n");
		if (atomic_read(&caifd->in_use))
			netdev_warn(dev,
				    "Unregistering an active CAIF device\n");
		cfcnfg_del_phy_layer(cfg, &caifd->layer);
		dev_put(dev);
		atomic_set(&caifd->state, what);
		break;

	case NETDEV_UNREGISTER:
		caifd = caif_get(dev);