diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-hsi | 19 | ||||
-rw-r--r-- | drivers/hsi/clients/hsi_char.c | 2 | ||||
-rw-r--r-- | drivers/hsi/hsi.c | 223 | ||||
-rw-r--r-- | include/linux/hsi/hsi.h | 31 |
4 files changed, 155 insertions, 120 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-hsi b/Documentation/ABI/testing/sysfs-bus-hsi new file mode 100644 index 000000000000..1b1b282a99e1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-hsi | |||
@@ -0,0 +1,19 @@ | |||
1 | What: /sys/bus/hsi | ||
2 | Date: April 2012 | ||
3 | KernelVersion: 3.4 | ||
4 | Contact: Carlos Chinea <carlos.chinea@nokia.com> | ||
5 | Description: | ||
6 | High Speed Synchronous Serial Interface (HSI) is a | ||
7 | serial interface mainly used for connecting application | ||
8 | engines (APE) with cellular modem engines (CMT) in cellular | ||
9 | handsets. | ||
10 | The bus will be populated with devices (hsi_clients) representing | ||
11 | the protocols available in the system. Bus drivers implement | ||
12 | those protocols. | ||
13 | |||
14 | What: /sys/bus/hsi/devices/.../modalias | ||
15 | Date: April 2012 | ||
16 | KernelVersion: 3.4 | ||
17 | Contact: Carlos Chinea <carlos.chinea@nokia.com> | ||
18 | Description: Stores the same MODALIAS value emitted by uevent | ||
19 | Format: hsi:<hsi_client device name> | ||
diff --git a/drivers/hsi/clients/hsi_char.c b/drivers/hsi/clients/hsi_char.c index 88a050df2389..3ad91f6447d8 100644 --- a/drivers/hsi/clients/hsi_char.c +++ b/drivers/hsi/clients/hsi_char.c | |||
@@ -123,7 +123,7 @@ struct hsc_client_data { | |||
123 | static unsigned int hsc_major; | 123 | static unsigned int hsc_major; |
124 | /* Maximum buffer size that hsi_char will accept from userspace */ | 124 | /* Maximum buffer size that hsi_char will accept from userspace */ |
125 | static unsigned int max_data_size = 0x1000; | 125 | static unsigned int max_data_size = 0x1000; |
126 | module_param(max_data_size, uint, S_IRUSR | S_IWUSR); | 126 | module_param(max_data_size, uint, 0); |
127 | MODULE_PARM_DESC(max_data_size, "max read/write data size [4,8..65536] (^2)"); | 127 | MODULE_PARM_DESC(max_data_size, "max read/write data size [4,8..65536] (^2)"); |
128 | 128 | ||
129 | static void hsc_add_tail(struct hsc_channel *channel, struct hsi_msg *msg, | 129 | static void hsc_add_tail(struct hsc_channel *channel, struct hsi_msg *msg, |
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c index 4e2d79b79334..2d58f939d27f 100644 --- a/drivers/hsi/hsi.c +++ b/drivers/hsi/hsi.c | |||
@@ -21,26 +21,13 @@ | |||
21 | */ | 21 | */ |
22 | #include <linux/hsi/hsi.h> | 22 | #include <linux/hsi/hsi.h> |
23 | #include <linux/compiler.h> | 23 | #include <linux/compiler.h> |
24 | #include <linux/rwsem.h> | ||
25 | #include <linux/list.h> | 24 | #include <linux/list.h> |
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/kobject.h> | 25 | #include <linux/kobject.h> |
28 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
29 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/notifier.h> | ||
30 | #include "hsi_core.h" | 29 | #include "hsi_core.h" |
31 | 30 | ||
32 | static struct device_type hsi_ctrl = { | ||
33 | .name = "hsi_controller", | ||
34 | }; | ||
35 | |||
36 | static struct device_type hsi_cl = { | ||
37 | .name = "hsi_client", | ||
38 | }; | ||
39 | |||
40 | static struct device_type hsi_port = { | ||
41 | .name = "hsi_port", | ||
42 | }; | ||
43 | |||
44 | static ssize_t modalias_show(struct device *dev, | 31 | static ssize_t modalias_show(struct device *dev, |
45 | struct device_attribute *a __maybe_unused, char *buf) | 32 | struct device_attribute *a __maybe_unused, char *buf) |
46 | { | 33 | { |
@@ -54,8 +41,7 @@ static struct device_attribute hsi_bus_dev_attrs[] = { | |||
54 | 41 | ||
55 | static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | 42 | static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) |
56 | { | 43 | { |
57 | if (dev->type == &hsi_cl) | 44 | add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev)); |
58 | add_uevent_var(env, "MODALIAS=hsi:%s", dev_name(dev)); | ||
59 | 45 | ||
60 | return 0; | 46 | return 0; |
61 | } | 47 | } |
@@ -80,12 +66,10 @@ static void hsi_client_release(struct device *dev) | |||
80 | static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) | 66 | static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) |
81 | { | 67 | { |
82 | struct hsi_client *cl; | 68 | struct hsi_client *cl; |
83 | unsigned long flags; | ||
84 | 69 | ||
85 | cl = kzalloc(sizeof(*cl), GFP_KERNEL); | 70 | cl = kzalloc(sizeof(*cl), GFP_KERNEL); |
86 | if (!cl) | 71 | if (!cl) |
87 | return; | 72 | return; |
88 | cl->device.type = &hsi_cl; | ||
89 | cl->tx_cfg = info->tx_cfg; | 73 | cl->tx_cfg = info->tx_cfg; |
90 | cl->rx_cfg = info->rx_cfg; | 74 | cl->rx_cfg = info->rx_cfg; |
91 | cl->device.bus = &hsi_bus_type; | 75 | cl->device.bus = &hsi_bus_type; |
@@ -93,14 +77,11 @@ static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info) | |||
93 | cl->device.release = hsi_client_release; | 77 | cl->device.release = hsi_client_release; |
94 | dev_set_name(&cl->device, info->name); | 78 | dev_set_name(&cl->device, info->name); |
95 | cl->device.platform_data = info->platform_data; | 79 | cl->device.platform_data = info->platform_data; |
96 | spin_lock_irqsave(&port->clock, flags); | ||
97 | list_add_tail(&cl->link, &port->clients); | ||
98 | spin_unlock_irqrestore(&port->clock, flags); | ||
99 | if (info->archdata) | 80 | if (info->archdata) |
100 | cl->device.archdata = *info->archdata; | 81 | cl->device.archdata = *info->archdata; |
101 | if (device_register(&cl->device) < 0) { | 82 | if (device_register(&cl->device) < 0) { |
102 | pr_err("hsi: failed to register client: %s\n", info->name); | 83 | pr_err("hsi: failed to register client: %s\n", info->name); |
103 | kfree(cl); | 84 | put_device(&cl->device); |
104 | } | 85 | } |
105 | } | 86 | } |
106 | 87 | ||
@@ -120,13 +101,6 @@ static void hsi_scan_board_info(struct hsi_controller *hsi) | |||
120 | 101 | ||
121 | static int hsi_remove_client(struct device *dev, void *data __maybe_unused) | 102 | static int hsi_remove_client(struct device *dev, void *data __maybe_unused) |
122 | { | 103 | { |
123 | struct hsi_client *cl = to_hsi_client(dev); | ||
124 | struct hsi_port *port = to_hsi_port(dev->parent); | ||
125 | unsigned long flags; | ||
126 | |||
127 | spin_lock_irqsave(&port->clock, flags); | ||
128 | list_del(&cl->link); | ||
129 | spin_unlock_irqrestore(&port->clock, flags); | ||
130 | device_unregister(dev); | 104 | device_unregister(dev); |
131 | 105 | ||
132 | return 0; | 106 | return 0; |
@@ -140,12 +114,17 @@ static int hsi_remove_port(struct device *dev, void *data __maybe_unused) | |||
140 | return 0; | 114 | return 0; |
141 | } | 115 | } |
142 | 116 | ||
143 | static void hsi_controller_release(struct device *dev __maybe_unused) | 117 | static void hsi_controller_release(struct device *dev) |
144 | { | 118 | { |
119 | struct hsi_controller *hsi = to_hsi_controller(dev); | ||
120 | |||
121 | kfree(hsi->port); | ||
122 | kfree(hsi); | ||
145 | } | 123 | } |
146 | 124 | ||
147 | static void hsi_port_release(struct device *dev __maybe_unused) | 125 | static void hsi_port_release(struct device *dev) |
148 | { | 126 | { |
127 | kfree(to_hsi_port(dev)); | ||
149 | } | 128 | } |
150 | 129 | ||
151 | /** | 130 | /** |
@@ -170,20 +149,12 @@ int hsi_register_controller(struct hsi_controller *hsi) | |||
170 | unsigned int i; | 149 | unsigned int i; |
171 | int err; | 150 | int err; |
172 | 151 | ||
173 | hsi->device.type = &hsi_ctrl; | 152 | err = device_add(&hsi->device); |
174 | hsi->device.bus = &hsi_bus_type; | ||
175 | hsi->device.release = hsi_controller_release; | ||
176 | err = device_register(&hsi->device); | ||
177 | if (err < 0) | 153 | if (err < 0) |
178 | return err; | 154 | return err; |
179 | for (i = 0; i < hsi->num_ports; i++) { | 155 | for (i = 0; i < hsi->num_ports; i++) { |
180 | hsi->port[i].device.parent = &hsi->device; | 156 | hsi->port[i]->device.parent = &hsi->device; |
181 | hsi->port[i].device.bus = &hsi_bus_type; | 157 | err = device_add(&hsi->port[i]->device); |
182 | hsi->port[i].device.release = hsi_port_release; | ||
183 | hsi->port[i].device.type = &hsi_port; | ||
184 | INIT_LIST_HEAD(&hsi->port[i].clients); | ||
185 | spin_lock_init(&hsi->port[i].clock); | ||
186 | err = device_register(&hsi->port[i].device); | ||
187 | if (err < 0) | 158 | if (err < 0) |
188 | goto out; | 159 | goto out; |
189 | } | 160 | } |
@@ -192,7 +163,9 @@ int hsi_register_controller(struct hsi_controller *hsi) | |||
192 | 163 | ||
193 | return 0; | 164 | return 0; |
194 | out: | 165 | out: |
195 | hsi_unregister_controller(hsi); | 166 | while (i-- > 0) |
167 | device_del(&hsi->port[i]->device); | ||
168 | device_del(&hsi->device); | ||
196 | 169 | ||
197 | return err; | 170 | return err; |
198 | } | 171 | } |
@@ -223,6 +196,29 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) | |||
223 | } | 196 | } |
224 | 197 | ||
225 | /** | 198 | /** |
199 | * hsi_put_controller - Free an HSI controller | ||
200 | * | ||
201 | * @hsi: Pointer to the HSI controller to freed | ||
202 | * | ||
203 | * HSI controller drivers should only use this function if they need | ||
204 | * to free their allocated hsi_controller structures before a successful | ||
205 | * call to hsi_register_controller. Other use is not allowed. | ||
206 | */ | ||
207 | void hsi_put_controller(struct hsi_controller *hsi) | ||
208 | { | ||
209 | unsigned int i; | ||
210 | |||
211 | if (!hsi) | ||
212 | return; | ||
213 | |||
214 | for (i = 0; i < hsi->num_ports; i++) | ||
215 | if (hsi->port && hsi->port[i]) | ||
216 | put_device(&hsi->port[i]->device); | ||
217 | put_device(&hsi->device); | ||
218 | } | ||
219 | EXPORT_SYMBOL_GPL(hsi_put_controller); | ||
220 | |||
221 | /** | ||
226 | * hsi_alloc_controller - Allocate an HSI controller and its ports | 222 | * hsi_alloc_controller - Allocate an HSI controller and its ports |
227 | * @n_ports: Number of ports on the HSI controller | 223 | * @n_ports: Number of ports on the HSI controller |
228 | * @flags: Kernel allocation flags | 224 | * @flags: Kernel allocation flags |
@@ -232,55 +228,52 @@ static inline int hsi_dummy_cl(struct hsi_client *cl __maybe_unused) | |||
232 | struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) | 228 | struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags) |
233 | { | 229 | { |
234 | struct hsi_controller *hsi; | 230 | struct hsi_controller *hsi; |
235 | struct hsi_port *port; | 231 | struct hsi_port **port; |
236 | unsigned int i; | 232 | unsigned int i; |
237 | 233 | ||
238 | if (!n_ports) | 234 | if (!n_ports) |
239 | return NULL; | 235 | return NULL; |
240 | 236 | ||
241 | port = kzalloc(sizeof(*port)*n_ports, flags); | ||
242 | if (!port) | ||
243 | return NULL; | ||
244 | hsi = kzalloc(sizeof(*hsi), flags); | 237 | hsi = kzalloc(sizeof(*hsi), flags); |
245 | if (!hsi) | 238 | if (!hsi) |
246 | goto out; | 239 | return NULL; |
247 | for (i = 0; i < n_ports; i++) { | 240 | port = kzalloc(sizeof(*port)*n_ports, flags); |
248 | dev_set_name(&port[i].device, "port%d", i); | 241 | if (!port) { |
249 | port[i].num = i; | 242 | kfree(hsi); |
250 | port[i].async = hsi_dummy_msg; | 243 | return NULL; |
251 | port[i].setup = hsi_dummy_cl; | ||
252 | port[i].flush = hsi_dummy_cl; | ||
253 | port[i].start_tx = hsi_dummy_cl; | ||
254 | port[i].stop_tx = hsi_dummy_cl; | ||
255 | port[i].release = hsi_dummy_cl; | ||
256 | mutex_init(&port[i].lock); | ||
257 | } | 244 | } |
258 | hsi->num_ports = n_ports; | 245 | hsi->num_ports = n_ports; |
259 | hsi->port = port; | 246 | hsi->port = port; |
247 | hsi->device.release = hsi_controller_release; | ||
248 | device_initialize(&hsi->device); | ||
249 | |||
250 | for (i = 0; i < n_ports; i++) { | ||
251 | port[i] = kzalloc(sizeof(**port), flags); | ||
252 | if (port[i] == NULL) | ||
253 | goto out; | ||
254 | port[i]->num = i; | ||
255 | port[i]->async = hsi_dummy_msg; | ||
256 | port[i]->setup = hsi_dummy_cl; | ||
257 | port[i]->flush = hsi_dummy_cl; | ||
258 | port[i]->start_tx = hsi_dummy_cl; | ||
259 | port[i]->stop_tx = hsi_dummy_cl; | ||
260 | port[i]->release = hsi_dummy_cl; | ||
261 | mutex_init(&port[i]->lock); | ||
262 | ATOMIC_INIT_NOTIFIER_HEAD(&port[i]->n_head); | ||
263 | dev_set_name(&port[i]->device, "port%d", i); | ||
264 | hsi->port[i]->device.release = hsi_port_release; | ||
265 | device_initialize(&hsi->port[i]->device); | ||
266 | } | ||
260 | 267 | ||
261 | return hsi; | 268 | return hsi; |
262 | out: | 269 | out: |
263 | kfree(port); | 270 | hsi_put_controller(hsi); |
264 | 271 | ||
265 | return NULL; | 272 | return NULL; |
266 | } | 273 | } |
267 | EXPORT_SYMBOL_GPL(hsi_alloc_controller); | 274 | EXPORT_SYMBOL_GPL(hsi_alloc_controller); |
268 | 275 | ||
269 | /** | 276 | /** |
270 | * hsi_free_controller - Free an HSI controller | ||
271 | * @hsi: Pointer to HSI controller | ||
272 | */ | ||
273 | void hsi_free_controller(struct hsi_controller *hsi) | ||
274 | { | ||
275 | if (!hsi) | ||
276 | return; | ||
277 | |||
278 | kfree(hsi->port); | ||
279 | kfree(hsi); | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(hsi_free_controller); | ||
282 | |||
283 | /** | ||
284 | * hsi_free_msg - Free an HSI message | 277 | * hsi_free_msg - Free an HSI message |
285 | * @msg: Pointer to the HSI message | 278 | * @msg: Pointer to the HSI message |
286 | * | 279 | * |
@@ -414,37 +407,67 @@ void hsi_release_port(struct hsi_client *cl) | |||
414 | } | 407 | } |
415 | EXPORT_SYMBOL_GPL(hsi_release_port); | 408 | EXPORT_SYMBOL_GPL(hsi_release_port); |
416 | 409 | ||
417 | static int hsi_start_rx(struct hsi_client *cl, void *data __maybe_unused) | 410 | static int hsi_event_notifier_call(struct notifier_block *nb, |
411 | unsigned long event, void *data __maybe_unused) | ||
418 | { | 412 | { |
419 | if (cl->hsi_start_rx) | 413 | struct hsi_client *cl = container_of(nb, struct hsi_client, nb); |
420 | (*cl->hsi_start_rx)(cl); | 414 | |
415 | (*cl->ehandler)(cl, event); | ||
421 | 416 | ||
422 | return 0; | 417 | return 0; |
423 | } | 418 | } |
424 | 419 | ||
425 | static int hsi_stop_rx(struct hsi_client *cl, void *data __maybe_unused) | 420 | /** |
421 | * hsi_register_port_event - Register a client to receive port events | ||
422 | * @cl: HSI client that wants to receive port events | ||
423 | * @cb: Event handler callback | ||
424 | * | ||
425 | * Clients should register a callback to be able to receive | ||
426 | * events from the ports. Registration should happen after | ||
427 | * claiming the port. | ||
428 | * The handler can be called in interrupt context. | ||
429 | * | ||
430 | * Returns -errno on error, or 0 on success. | ||
431 | */ | ||
432 | int hsi_register_port_event(struct hsi_client *cl, | ||
433 | void (*handler)(struct hsi_client *, unsigned long)) | ||
426 | { | 434 | { |
427 | if (cl->hsi_stop_rx) | 435 | struct hsi_port *port = hsi_get_port(cl); |
428 | (*cl->hsi_stop_rx)(cl); | ||
429 | 436 | ||
430 | return 0; | 437 | if (!handler || cl->ehandler) |
438 | return -EINVAL; | ||
439 | if (!hsi_port_claimed(cl)) | ||
440 | return -EACCES; | ||
441 | cl->ehandler = handler; | ||
442 | cl->nb.notifier_call = hsi_event_notifier_call; | ||
443 | |||
444 | return atomic_notifier_chain_register(&port->n_head, &cl->nb); | ||
431 | } | 445 | } |
446 | EXPORT_SYMBOL_GPL(hsi_register_port_event); | ||
432 | 447 | ||
433 | static int hsi_port_for_each_client(struct hsi_port *port, void *data, | 448 | /** |
434 | int (*fn)(struct hsi_client *cl, void *data)) | 449 | * hsi_unregister_port_event - Stop receiving port events for a client |
450 | * @cl: HSI client that wants to stop receiving port events | ||
451 | * | ||
452 | * Clients should call this function before releasing their associated | ||
453 | * port. | ||
454 | * | ||
455 | * Returns -errno on error, or 0 on success. | ||
456 | */ | ||
457 | int hsi_unregister_port_event(struct hsi_client *cl) | ||
435 | { | 458 | { |
436 | struct hsi_client *cl; | 459 | struct hsi_port *port = hsi_get_port(cl); |
460 | int err; | ||
437 | 461 | ||
438 | spin_lock(&port->clock); | 462 | WARN_ON(!hsi_port_claimed(cl)); |
439 | list_for_each_entry(cl, &port->clients, link) { | ||
440 | spin_unlock(&port->clock); | ||
441 | (*fn)(cl, data); | ||
442 | spin_lock(&port->clock); | ||
443 | } | ||
444 | spin_unlock(&port->clock); | ||
445 | 463 | ||
446 | return 0; | 464 | err = atomic_notifier_chain_unregister(&port->n_head, &cl->nb); |
465 | if (!err) | ||
466 | cl->ehandler = NULL; | ||
467 | |||
468 | return err; | ||
447 | } | 469 | } |
470 | EXPORT_SYMBOL_GPL(hsi_unregister_port_event); | ||
448 | 471 | ||
449 | /** | 472 | /** |
450 | * hsi_event -Notifies clients about port events | 473 | * hsi_event -Notifies clients about port events |
@@ -458,22 +481,12 @@ static int hsi_port_for_each_client(struct hsi_port *port, void *data, | |||
458 | * Events: | 481 | * Events: |
459 | * HSI_EVENT_START_RX - Incoming wake line high | 482 | * HSI_EVENT_START_RX - Incoming wake line high |
460 | * HSI_EVENT_STOP_RX - Incoming wake line down | 483 | * HSI_EVENT_STOP_RX - Incoming wake line down |
484 | * | ||
485 | * Returns -errno on error, or 0 on success. | ||
461 | */ | 486 | */ |
462 | void hsi_event(struct hsi_port *port, unsigned int event) | 487 | int hsi_event(struct hsi_port *port, unsigned long event) |
463 | { | 488 | { |
464 | int (*fn)(struct hsi_client *cl, void *data); | 489 | return atomic_notifier_call_chain(&port->n_head, event, NULL); |
465 | |||
466 | switch (event) { | ||
467 | case HSI_EVENT_START_RX: | ||
468 | fn = hsi_start_rx; | ||
469 | break; | ||
470 | case HSI_EVENT_STOP_RX: | ||
471 | fn = hsi_stop_rx; | ||
472 | break; | ||
473 | default: | ||
474 | return; | ||
475 | } | ||
476 | hsi_port_for_each_client(port, NULL, fn); | ||
477 | } | 490 | } |
478 | EXPORT_SYMBOL_GPL(hsi_event); | 491 | EXPORT_SYMBOL_GPL(hsi_event); |
479 | 492 | ||
diff --git a/include/linux/hsi/hsi.h b/include/linux/hsi/hsi.h index 4b178067f405..56fae865e272 100644 --- a/include/linux/hsi/hsi.h +++ b/include/linux/hsi/hsi.h | |||
@@ -26,9 +26,9 @@ | |||
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/scatterlist.h> | 28 | #include <linux/scatterlist.h> |
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/list.h> | 29 | #include <linux/list.h> |
31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/notifier.h> | ||
32 | 32 | ||
33 | /* HSI message ttype */ | 33 | /* HSI message ttype */ |
34 | #define HSI_MSG_READ 0 | 34 | #define HSI_MSG_READ 0 |
@@ -121,18 +121,18 @@ static inline int hsi_register_board_info(struct hsi_board_info const *info, | |||
121 | * @device: Driver model representation of the device | 121 | * @device: Driver model representation of the device |
122 | * @tx_cfg: HSI TX configuration | 122 | * @tx_cfg: HSI TX configuration |
123 | * @rx_cfg: HSI RX configuration | 123 | * @rx_cfg: HSI RX configuration |
124 | * @hsi_start_rx: Called after incoming wake line goes high | 124 | * @e_handler: Callback for handling port events (RX Wake High/Low) |
125 | * @hsi_stop_rx: Called after incoming wake line goes low | 125 | * @pclaimed: Keeps tracks if the clients claimed its associated HSI port |
126 | * @nb: Notifier block for port events | ||
126 | */ | 127 | */ |
127 | struct hsi_client { | 128 | struct hsi_client { |
128 | struct device device; | 129 | struct device device; |
129 | struct hsi_config tx_cfg; | 130 | struct hsi_config tx_cfg; |
130 | struct hsi_config rx_cfg; | 131 | struct hsi_config rx_cfg; |
131 | void (*hsi_start_rx)(struct hsi_client *cl); | ||
132 | void (*hsi_stop_rx)(struct hsi_client *cl); | ||
133 | /* private: */ | 132 | /* private: */ |
133 | void (*ehandler)(struct hsi_client *, unsigned long); | ||
134 | unsigned int pclaimed:1; | 134 | unsigned int pclaimed:1; |
135 | struct list_head link; | 135 | struct notifier_block nb; |
136 | }; | 136 | }; |
137 | 137 | ||
138 | #define to_hsi_client(dev) container_of(dev, struct hsi_client, device) | 138 | #define to_hsi_client(dev) container_of(dev, struct hsi_client, device) |
@@ -147,6 +147,10 @@ static inline void *hsi_client_drvdata(struct hsi_client *cl) | |||
147 | return dev_get_drvdata(&cl->device); | 147 | return dev_get_drvdata(&cl->device); |
148 | } | 148 | } |
149 | 149 | ||
150 | int hsi_register_port_event(struct hsi_client *cl, | ||
151 | void (*handler)(struct hsi_client *, unsigned long)); | ||
152 | int hsi_unregister_port_event(struct hsi_client *cl); | ||
153 | |||
150 | /** | 154 | /** |
151 | * struct hsi_client_driver - Driver associated to an HSI client | 155 | * struct hsi_client_driver - Driver associated to an HSI client |
152 | * @driver: Driver model representation of the driver | 156 | * @driver: Driver model representation of the driver |
@@ -214,8 +218,7 @@ void hsi_free_msg(struct hsi_msg *msg); | |||
214 | * @start_tx: Callback to inform that a client wants to TX data | 218 | * @start_tx: Callback to inform that a client wants to TX data |
215 | * @stop_tx: Callback to inform that a client no longer wishes to TX data | 219 | * @stop_tx: Callback to inform that a client no longer wishes to TX data |
216 | * @release: Callback to inform that a client no longer uses the port | 220 | * @release: Callback to inform that a client no longer uses the port |
217 | * @clients: List of hsi_clients using the port. | 221 | * @n_head: Notifier chain for signaling port events to the clients. |
218 | * @clock: Lock to serialize access to the clients list. | ||
219 | */ | 222 | */ |
220 | struct hsi_port { | 223 | struct hsi_port { |
221 | struct device device; | 224 | struct device device; |
@@ -231,14 +234,14 @@ struct hsi_port { | |||
231 | int (*start_tx)(struct hsi_client *cl); | 234 | int (*start_tx)(struct hsi_client *cl); |
232 | int (*stop_tx)(struct hsi_client *cl); | 235 | int (*stop_tx)(struct hsi_client *cl); |
233 | int (*release)(struct hsi_client *cl); | 236 | int (*release)(struct hsi_client *cl); |
234 | struct list_head clients; | 237 | /* private */ |
235 | spinlock_t clock; | 238 | struct atomic_notifier_head n_head; |
236 | }; | 239 | }; |
237 | 240 | ||
238 | #define to_hsi_port(dev) container_of(dev, struct hsi_port, device) | 241 | #define to_hsi_port(dev) container_of(dev, struct hsi_port, device) |
239 | #define hsi_get_port(cl) to_hsi_port((cl)->device.parent) | 242 | #define hsi_get_port(cl) to_hsi_port((cl)->device.parent) |
240 | 243 | ||
241 | void hsi_event(struct hsi_port *port, unsigned int event); | 244 | int hsi_event(struct hsi_port *port, unsigned long event); |
242 | int hsi_claim_port(struct hsi_client *cl, unsigned int share); | 245 | int hsi_claim_port(struct hsi_client *cl, unsigned int share); |
243 | void hsi_release_port(struct hsi_client *cl); | 246 | void hsi_release_port(struct hsi_client *cl); |
244 | 247 | ||
@@ -270,13 +273,13 @@ struct hsi_controller { | |||
270 | struct module *owner; | 273 | struct module *owner; |
271 | unsigned int id; | 274 | unsigned int id; |
272 | unsigned int num_ports; | 275 | unsigned int num_ports; |
273 | struct hsi_port *port; | 276 | struct hsi_port **port; |
274 | }; | 277 | }; |
275 | 278 | ||
276 | #define to_hsi_controller(dev) container_of(dev, struct hsi_controller, device) | 279 | #define to_hsi_controller(dev) container_of(dev, struct hsi_controller, device) |
277 | 280 | ||
278 | struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags); | 281 | struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags); |
279 | void hsi_free_controller(struct hsi_controller *hsi); | 282 | void hsi_put_controller(struct hsi_controller *hsi); |
280 | int hsi_register_controller(struct hsi_controller *hsi); | 283 | int hsi_register_controller(struct hsi_controller *hsi); |
281 | void hsi_unregister_controller(struct hsi_controller *hsi); | 284 | void hsi_unregister_controller(struct hsi_controller *hsi); |
282 | 285 | ||
@@ -294,7 +297,7 @@ static inline void *hsi_controller_drvdata(struct hsi_controller *hsi) | |||
294 | static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi, | 297 | static inline struct hsi_port *hsi_find_port_num(struct hsi_controller *hsi, |
295 | unsigned int num) | 298 | unsigned int num) |
296 | { | 299 | { |
297 | return (num < hsi->num_ports) ? &hsi->port[num] : NULL; | 300 | return (num < hsi->num_ports) ? hsi->port[num] : NULL; |
298 | } | 301 | } |
299 | 302 | ||
300 | /* | 303 | /* |