Home Home > GIT Browse
summaryrefslogtreecommitdiff
blob: 138a5efe863a3cb569de62fe00f93bbe38051279 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
 * Copyright (C) 1999-2002 Vojtech Pavlik
*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */
#ifndef _SERIO_H
#define _SERIO_H


#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <uapi/linux/serio.h>

extern struct bus_type serio_bus;

struct serio {
	void *port_data;

	char name[32];
	char phys[32];
	char firmware_id[128];

	bool manual_bind;

	struct serio_device_id id;

	/* Protects critical sections from port's interrupt handler */
	spinlock_t lock;

	int (*write)(struct serio *, unsigned char);
	int (*open)(struct serio *);
	void (*close)(struct serio *);
	int (*start)(struct serio *);
	void (*stop)(struct serio *);

	struct serio *parent;
	/* Entry in parent->children list */
	struct list_head child_node;
	struct list_head children;
	/* Level of nesting in serio hierarchy */
	unsigned int depth;

	/*
	 * serio->drv is accessed from interrupt handlers; when modifying
	 * caller should acquire serio->drv_mutex and serio->lock.
	 */
	struct serio_driver *drv;
	/* Protects serio->drv so attributes can pin current driver */
	struct mutex drv_mutex;

	struct device dev;

	struct list_head node;

	/*
	 * For use by PS/2 layer when several ports share hardware and
	 * may get indigestion when exposed to concurrent access (i8042).
	 */
	struct mutex *ps2_cmd_mutex;
};
#define to_serio_port(d)	container_of(d, struct serio, dev)

struct serio_driver {
	const char *description;

	const struct serio_device_id *id_table;
	bool manual_bind;

	void (*write_wakeup)(struct serio *);
	irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int);
	int  (*connect)(struct serio *, struct serio_driver *drv);
	int  (*reconnect)(struct serio *);
	int  (*fast_reconnect)(struct serio *);
	void (*disconnect)(struct serio *);
	void (*cleanup)(struct serio *);

	struct device_driver driver;
};
#define to_serio_driver(d)	container_of(d, struct serio_driver, driver)

int serio_open(struct serio *serio, struct serio_driver *drv);
void serio_close(struct serio *serio);
void serio_rescan(struct serio *serio);
void serio_reconnect(struct serio *serio);
irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags);

void __serio_register_port(struct serio *serio, struct module *owner);

/* use a define to avoid include chaining to get THIS_MODULE */
#define serio_register_port(serio) \
	__serio_register_port(serio, THIS_MODULE)

void serio_unregister_port(struct serio *serio);
void serio_unregister_child_port(struct serio *serio);

int __must_check __serio_register_driver(struct serio_driver *drv,
				struct module *owner, const char *mod_name);

/* use a define to avoid include chaining to get THIS_MODULE & friends */
#define serio_register_driver(drv) \
	__serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME)

void serio_unregister_driver(struct serio_driver *drv);

/**
 * module_serio_driver() - Helper macro for registering a serio driver
 * @__serio_driver: serio_driver struct
 *
 * Helper macro for serio drivers which do not do anything special in
 * module init/exit. This eliminates a lot of boilerplate. Each module
 * may only use this macro once, and calling it replaces module_init()
 * and module_exit().
 */
#define module_serio_driver(__serio_driver) \
	module_driver(__serio_driver, serio_register_driver, \
		       serio_unregister_driver)

static inline int serio_write(struct serio *serio, unsigned char data)
{
	if (serio->write)
		return serio->write(serio, data);
	else
		return -1;
}

static inline void serio_drv_write_wakeup(struct serio *serio)
{
	if (serio->drv && serio->drv->write_wakeup)
		serio->drv->write_wakeup(serio);
}

/*
 * Use the following functions to manipulate serio's per-port
 * driver-specific data.
 */
static inline void *serio_get_drvdata(struct serio *serio)
{
	return dev_get_drvdata(&serio->dev);
}

static inline void serio_set_drvdata(struct serio *serio, void *data)
{
	dev_set_drvdata(&serio->dev, data);
}

/*
 * Use the following functions to protect critical sections in
 * driver code from port's interrupt handler
 */
static inline void serio_pause_rx(struct serio *serio)
{
	spin_lock_irq(&serio->lock);
}

static inline void serio_continue_rx(struct serio *serio)
{
	spin_unlock_irq(&serio->lock);
}

#endif