diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch')
-rw-r--r-- | extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch new file mode 100644 index 00000000..c16dc453 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch | |||
@@ -0,0 +1,900 @@ | |||
1 | From 46b2c4077bedb96a38cdceff88f2c9b0a9923a8c Mon Sep 17 00:00:00 2001 | ||
2 | From: Pavan Savoy <pavan_savoy@ti.com> | ||
3 | Date: Tue, 4 Jan 2011 10:59:47 +0000 | ||
4 | Subject: [PATCH 14/15] drivers:misc:ti-st: change protocol parse logic | ||
5 | |||
6 | TI shared transport driver had to specifically know the | ||
7 | protocol headers for each type of data it can receive to | ||
8 | properly re-assemble data if its fragmented during UART | ||
9 | transaction or fragment if the data is an assembly of | ||
10 | |||
11 | different protocol data. | ||
12 | |||
13 | Now the individual protocol drivers provide enough header | ||
14 | information for shared transport driver to do this in a | ||
15 | generic way applicable for all protocols. | ||
16 | |||
17 | Signed-off-by: Pavan Savoy <pavan_savoy@ti.com> | ||
18 | --- | ||
19 | drivers/misc/ti-st/st_core.c | 355 +++++++++++++----------------------------- | ||
20 | drivers/misc/ti-st/st_kim.c | 56 ++++---- | ||
21 | include/linux/ti_wilink_st.h | 40 ++++-- | ||
22 | 3 files changed, 167 insertions(+), 284 deletions(-) | ||
23 | |||
24 | diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c | ||
25 | index f9aad06..84d73c5 100644 | ||
26 | --- a/drivers/misc/ti-st/st_core.c | ||
27 | +++ b/drivers/misc/ti-st/st_core.c | ||
28 | @@ -25,10 +25,9 @@ | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/tty.h> | ||
31 | |||
32 | -/* understand BT, FM and GPS for now */ | ||
33 | -#include <net/bluetooth/bluetooth.h> | ||
34 | -#include <net/bluetooth/hci_core.h> | ||
35 | -#include <net/bluetooth/hci.h> | ||
36 | +#include <linux/seq_file.h> | ||
37 | +#include <linux/skbuff.h> | ||
38 | + | ||
39 | #include <linux/ti_wilink_st.h> | ||
40 | |||
41 | /* function pointer pointing to either, | ||
42 | @@ -38,21 +37,20 @@ | ||
43 | void (*st_recv) (void*, const unsigned char*, long); | ||
44 | |||
45 | /********************************************************************/ | ||
46 | -#if 0 | ||
47 | -/* internal misc functions */ | ||
48 | -bool is_protocol_list_empty(void) | ||
49 | +static void add_channel_to_table(struct st_data_s *st_gdata, | ||
50 | + struct st_proto_s *new_proto) | ||
51 | { | ||
52 | - unsigned char i = 0; | ||
53 | - pr_debug(" %s ", __func__); | ||
54 | - for (i = 0; i < ST_MAX; i++) { | ||
55 | - if (st_gdata->list[i] != NULL) | ||
56 | - return ST_NOTEMPTY; | ||
57 | - /* not empty */ | ||
58 | - } | ||
59 | - /* list empty */ | ||
60 | - return ST_EMPTY; | ||
61 | + pr_info("%s: id %d\n", __func__, new_proto->chnl_id); | ||
62 | + /* list now has the channel id as index itself */ | ||
63 | + st_gdata->list[new_proto->chnl_id] = new_proto; | ||
64 | +} | ||
65 | + | ||
66 | +static void remove_channel_from_table(struct st_data_s *st_gdata, | ||
67 | + struct st_proto_s *proto) | ||
68 | +{ | ||
69 | + pr_info("%s: id %d\n", __func__, proto->chnl_id); | ||
70 | + st_gdata->list[proto->chnl_id] = NULL; | ||
71 | } | ||
72 | -#endif | ||
73 | |||
74 | /* can be called in from | ||
75 | * -- KIM (during fw download) | ||
76 | @@ -82,15 +80,15 @@ int st_int_write(struct st_data_s *st_gdata, | ||
77 | * push the skb received to relevant | ||
78 | * protocol stacks | ||
79 | */ | ||
80 | -void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata) | ||
81 | +void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) | ||
82 | { | ||
83 | - pr_info(" %s(prot:%d) ", __func__, protoid); | ||
84 | + pr_info(" %s(prot:%d) ", __func__, chnl_id); | ||
85 | |||
86 | if (unlikely | ||
87 | (st_gdata == NULL || st_gdata->rx_skb == NULL | ||
88 | - || st_gdata->list[protoid] == NULL)) { | ||
89 | - pr_err("protocol %d not registered, no data to send?", | ||
90 | - protoid); | ||
91 | + || st_gdata->list[chnl_id] == NULL)) { | ||
92 | + pr_err("chnl_id %d not registered, no data to send?", | ||
93 | + chnl_id); | ||
94 | kfree_skb(st_gdata->rx_skb); | ||
95 | return; | ||
96 | } | ||
97 | @@ -99,17 +97,17 @@ void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata) | ||
98 | * - should be just skb_queue_tail for the | ||
99 | * protocol stack driver | ||
100 | */ | ||
101 | - if (likely(st_gdata->list[protoid]->recv != NULL)) { | ||
102 | + if (likely(st_gdata->list[chnl_id]->recv != NULL)) { | ||
103 | if (unlikely | ||
104 | - (st_gdata->list[protoid]->recv | ||
105 | - (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb) | ||
106 | + (st_gdata->list[chnl_id]->recv | ||
107 | + (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) | ||
108 | != 0)) { | ||
109 | - pr_err(" proto stack %d's ->recv failed", protoid); | ||
110 | + pr_err(" proto stack %d's ->recv failed", chnl_id); | ||
111 | kfree_skb(st_gdata->rx_skb); | ||
112 | return; | ||
113 | } | ||
114 | } else { | ||
115 | - pr_err(" proto stack %d's ->recv null", protoid); | ||
116 | + pr_err(" proto stack %d's ->recv null", chnl_id); | ||
117 | kfree_skb(st_gdata->rx_skb); | ||
118 | } | ||
119 | return; | ||
120 | @@ -124,7 +122,7 @@ void st_reg_complete(struct st_data_s *st_gdata, char err) | ||
121 | { | ||
122 | unsigned char i = 0; | ||
123 | pr_info(" %s ", __func__); | ||
124 | - for (i = 0; i < ST_MAX; i++) { | ||
125 | + for (i = 0; i < ST_MAX_CHANNELS; i++) { | ||
126 | if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && | ||
127 | st_gdata->list[i]->reg_complete_cb != NULL)) | ||
128 | st_gdata->list[i]->reg_complete_cb | ||
129 | @@ -133,7 +131,7 @@ void st_reg_complete(struct st_data_s *st_gdata, char err) | ||
130 | } | ||
131 | |||
132 | static inline int st_check_data_len(struct st_data_s *st_gdata, | ||
133 | - int protoid, int len) | ||
134 | + unsigned char chnl_id, int len) | ||
135 | { | ||
136 | int room = skb_tailroom(st_gdata->rx_skb); | ||
137 | |||
138 | @@ -144,7 +142,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata, | ||
139 | * has zero length payload. So, ask ST CORE to | ||
140 | * forward the packet to protocol driver (BT/FM/GPS) | ||
141 | */ | ||
142 | - st_send_frame(protoid, st_gdata); | ||
143 | + st_send_frame(chnl_id, st_gdata); | ||
144 | |||
145 | } else if (len > room) { | ||
146 | /* Received packet's payload length is larger. | ||
147 | @@ -157,7 +155,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata, | ||
148 | /* Packet header has non-zero payload length and | ||
149 | * we have enough space in created skb. Lets read | ||
150 | * payload data */ | ||
151 | - st_gdata->rx_state = ST_BT_W4_DATA; | ||
152 | + st_gdata->rx_state = ST_W4_DATA; | ||
153 | st_gdata->rx_count = len; | ||
154 | return len; | ||
155 | } | ||
156 | @@ -167,6 +165,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata, | ||
157 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
158 | st_gdata->rx_skb = NULL; | ||
159 | st_gdata->rx_count = 0; | ||
160 | + st_gdata->rx_chnl = 0; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | @@ -208,13 +207,10 @@ void st_int_recv(void *disc_data, | ||
165 | const unsigned char *data, long count) | ||
166 | { | ||
167 | char *ptr; | ||
168 | - struct hci_event_hdr *eh; | ||
169 | - struct hci_acl_hdr *ah; | ||
170 | - struct hci_sco_hdr *sh; | ||
171 | - struct fm_event_hdr *fm; | ||
172 | - struct gps_event_hdr *gps; | ||
173 | - int len = 0, type = 0, dlen = 0; | ||
174 | - static enum proto_type protoid = ST_MAX; | ||
175 | + struct st_proto_s *proto; | ||
176 | + unsigned short payload_len = 0; | ||
177 | + int len = 0, type = 0; | ||
178 | + unsigned char *plen; | ||
179 | struct st_data_s *st_gdata = (struct st_data_s *)disc_data; | ||
180 | |||
181 | ptr = (char *)data; | ||
182 | @@ -242,64 +238,36 @@ void st_int_recv(void *disc_data, | ||
183 | |||
184 | /* Check ST RX state machine , where are we? */ | ||
185 | switch (st_gdata->rx_state) { | ||
186 | - | ||
187 | - /* Waiting for complete packet ? */ | ||
188 | - case ST_BT_W4_DATA: | ||
189 | + /* Waiting for complete packet ? */ | ||
190 | + case ST_W4_DATA: | ||
191 | pr_debug("Complete pkt received"); | ||
192 | - | ||
193 | /* Ask ST CORE to forward | ||
194 | * the packet to protocol driver */ | ||
195 | - st_send_frame(protoid, st_gdata); | ||
196 | + st_send_frame(st_gdata->rx_chnl, st_gdata); | ||
197 | |||
198 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
199 | st_gdata->rx_skb = NULL; | ||
200 | - protoid = ST_MAX; /* is this required ? */ | ||
201 | - continue; | ||
202 | - | ||
203 | - /* Waiting for Bluetooth event header ? */ | ||
204 | - case ST_BT_W4_EVENT_HDR: | ||
205 | - eh = (struct hci_event_hdr *)st_gdata->rx_skb-> | ||
206 | - data; | ||
207 | - | ||
208 | - pr_debug("Event header: evt 0x%2.2x" | ||
209 | - "plen %d", eh->evt, eh->plen); | ||
210 | - | ||
211 | - st_check_data_len(st_gdata, protoid, eh->plen); | ||
212 | - continue; | ||
213 | - | ||
214 | - /* Waiting for Bluetooth acl header ? */ | ||
215 | - case ST_BT_W4_ACL_HDR: | ||
216 | - ah = (struct hci_acl_hdr *)st_gdata->rx_skb-> | ||
217 | - data; | ||
218 | - dlen = __le16_to_cpu(ah->dlen); | ||
219 | - | ||
220 | - pr_info("ACL header: dlen %d", dlen); | ||
221 | - | ||
222 | - st_check_data_len(st_gdata, protoid, dlen); | ||
223 | - continue; | ||
224 | - | ||
225 | - /* Waiting for Bluetooth sco header ? */ | ||
226 | - case ST_BT_W4_SCO_HDR: | ||
227 | - sh = (struct hci_sco_hdr *)st_gdata->rx_skb-> | ||
228 | - data; | ||
229 | - | ||
230 | - pr_info("SCO header: dlen %d", sh->dlen); | ||
231 | - | ||
232 | - st_check_data_len(st_gdata, protoid, sh->dlen); | ||
233 | - continue; | ||
234 | - case ST_FM_W4_EVENT_HDR: | ||
235 | - fm = (struct fm_event_hdr *)st_gdata->rx_skb-> | ||
236 | - data; | ||
237 | - pr_info("FM Header: "); | ||
238 | - st_check_data_len(st_gdata, ST_FM, fm->plen); | ||
239 | continue; | ||
240 | - /* TODO : Add GPS packet machine logic here */ | ||
241 | - case ST_GPS_W4_EVENT_HDR: | ||
242 | - /* [0x09 pkt hdr][R/W byte][2 byte len] */ | ||
243 | - gps = (struct gps_event_hdr *)st_gdata->rx_skb-> | ||
244 | - data; | ||
245 | - pr_info("GPS Header: "); | ||
246 | - st_check_data_len(st_gdata, ST_GPS, gps->plen); | ||
247 | + /* parse the header to know details */ | ||
248 | + case ST_W4_HEADER: | ||
249 | + proto = st_gdata->list[st_gdata->rx_chnl]; | ||
250 | + plen = | ||
251 | + &st_gdata->rx_skb->data | ||
252 | + [proto->offset_len_in_hdr]; | ||
253 | + pr_info("plen pointing to %x\n", *plen); | ||
254 | + if (proto->len_size == 1)/* 1 byte len field */ | ||
255 | + payload_len = *(unsigned char *)plen; | ||
256 | + else if (proto->len_size == 2) | ||
257 | + payload_len = | ||
258 | + __le16_to_cpu(*(unsigned short *)plen); | ||
259 | + else | ||
260 | + pr_info("%s: invalid length " | ||
261 | + "for id %d\n", | ||
262 | + __func__, proto->chnl_id); | ||
263 | + st_check_data_len(st_gdata, proto->chnl_id, | ||
264 | + payload_len); | ||
265 | + pr_info("off %d, pay len %d\n", | ||
266 | + proto->offset_len_in_hdr, payload_len); | ||
267 | continue; | ||
268 | } /* end of switch rx_state */ | ||
269 | } | ||
270 | @@ -308,51 +276,6 @@ void st_int_recv(void *disc_data, | ||
271 | /* Check first byte of packet and identify module | ||
272 | * owner (BT/FM/GPS) */ | ||
273 | switch (*ptr) { | ||
274 | - | ||
275 | - /* Bluetooth event packet? */ | ||
276 | - case HCI_EVENT_PKT: | ||
277 | - pr_info("Event packet"); | ||
278 | - st_gdata->rx_state = ST_BT_W4_EVENT_HDR; | ||
279 | - st_gdata->rx_count = HCI_EVENT_HDR_SIZE; | ||
280 | - type = HCI_EVENT_PKT; | ||
281 | - protoid = ST_BT; | ||
282 | - break; | ||
283 | - | ||
284 | - /* Bluetooth acl packet? */ | ||
285 | - case HCI_ACLDATA_PKT: | ||
286 | - pr_info("ACL packet"); | ||
287 | - st_gdata->rx_state = ST_BT_W4_ACL_HDR; | ||
288 | - st_gdata->rx_count = HCI_ACL_HDR_SIZE; | ||
289 | - type = HCI_ACLDATA_PKT; | ||
290 | - protoid = ST_BT; | ||
291 | - break; | ||
292 | - | ||
293 | - /* Bluetooth sco packet? */ | ||
294 | - case HCI_SCODATA_PKT: | ||
295 | - pr_info("SCO packet"); | ||
296 | - st_gdata->rx_state = ST_BT_W4_SCO_HDR; | ||
297 | - st_gdata->rx_count = HCI_SCO_HDR_SIZE; | ||
298 | - type = HCI_SCODATA_PKT; | ||
299 | - protoid = ST_BT; | ||
300 | - break; | ||
301 | - | ||
302 | - /* Channel 8(FM) packet? */ | ||
303 | - case ST_FM_CH8_PKT: | ||
304 | - pr_info("FM CH8 packet"); | ||
305 | - type = ST_FM_CH8_PKT; | ||
306 | - st_gdata->rx_state = ST_FM_W4_EVENT_HDR; | ||
307 | - st_gdata->rx_count = FM_EVENT_HDR_SIZE; | ||
308 | - protoid = ST_FM; | ||
309 | - break; | ||
310 | - | ||
311 | - /* Channel 9(GPS) packet? */ | ||
312 | - case 0x9: /*ST_LL_GPS_CH9_PKT */ | ||
313 | - pr_info("GPS CH9 packet"); | ||
314 | - type = 0x9; /* ST_LL_GPS_CH9_PKT; */ | ||
315 | - protoid = ST_GPS; | ||
316 | - st_gdata->rx_state = ST_GPS_W4_EVENT_HDR; | ||
317 | - st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/ | ||
318 | - break; | ||
319 | case LL_SLEEP_IND: | ||
320 | case LL_SLEEP_ACK: | ||
321 | case LL_WAKE_UP_IND: | ||
322 | @@ -373,57 +296,22 @@ void st_int_recv(void *disc_data, | ||
323 | continue; | ||
324 | /* Unknow packet? */ | ||
325 | default: | ||
326 | - pr_err("Unknown packet type %2.2x", (__u8) *ptr); | ||
327 | - ptr++; | ||
328 | - count--; | ||
329 | - continue; | ||
330 | + type = *ptr; | ||
331 | + st_gdata->rx_skb = alloc_skb( | ||
332 | + st_gdata->list[type]->max_frame_size, | ||
333 | + GFP_ATOMIC); | ||
334 | + skb_reserve(st_gdata->rx_skb, | ||
335 | + st_gdata->list[type]->reserve); | ||
336 | + /* next 2 required for BT only */ | ||
337 | + st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ | ||
338 | + st_gdata->rx_skb->cb[1] = 0; /*incoming*/ | ||
339 | + st_gdata->rx_chnl = *ptr; | ||
340 | + st_gdata->rx_state = ST_W4_HEADER; | ||
341 | + st_gdata->rx_count = st_gdata->list[type]->hdr_len; | ||
342 | + pr_info("rx_count %ld\n", st_gdata->rx_count); | ||
343 | }; | ||
344 | ptr++; | ||
345 | count--; | ||
346 | - | ||
347 | - switch (protoid) { | ||
348 | - case ST_BT: | ||
349 | - /* Allocate new packet to hold received data */ | ||
350 | - st_gdata->rx_skb = | ||
351 | - bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); | ||
352 | - if (!st_gdata->rx_skb) { | ||
353 | - pr_err("Can't allocate mem for new packet"); | ||
354 | - st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
355 | - st_gdata->rx_count = 0; | ||
356 | - return; | ||
357 | - } | ||
358 | - bt_cb(st_gdata->rx_skb)->pkt_type = type; | ||
359 | - break; | ||
360 | - case ST_FM: /* for FM */ | ||
361 | - st_gdata->rx_skb = | ||
362 | - alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC); | ||
363 | - if (!st_gdata->rx_skb) { | ||
364 | - pr_err("Can't allocate mem for new packet"); | ||
365 | - st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
366 | - st_gdata->rx_count = 0; | ||
367 | - return; | ||
368 | - } | ||
369 | - /* place holder 0x08 */ | ||
370 | - skb_reserve(st_gdata->rx_skb, 1); | ||
371 | - st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT; | ||
372 | - break; | ||
373 | - case ST_GPS: | ||
374 | - /* for GPS */ | ||
375 | - st_gdata->rx_skb = | ||
376 | - alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC); | ||
377 | - if (!st_gdata->rx_skb) { | ||
378 | - pr_err("Can't allocate mem for new packet"); | ||
379 | - st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
380 | - st_gdata->rx_count = 0; | ||
381 | - return; | ||
382 | - } | ||
383 | - /* place holder 0x09 */ | ||
384 | - skb_reserve(st_gdata->rx_skb, 1); | ||
385 | - st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */ | ||
386 | - break; | ||
387 | - case ST_MAX: | ||
388 | - break; | ||
389 | - } | ||
390 | } | ||
391 | pr_debug("done %s", __func__); | ||
392 | return; | ||
393 | @@ -565,20 +453,28 @@ long st_register(struct st_proto_s *new_proto) | ||
394 | unsigned long flags = 0; | ||
395 | |||
396 | st_kim_ref(&st_gdata, 0); | ||
397 | - pr_info("%s(%d) ", __func__, new_proto->type); | ||
398 | + pr_info("%s(%d) ", __func__, new_proto->chnl_id); | ||
399 | if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL | ||
400 | || new_proto->reg_complete_cb == NULL) { | ||
401 | pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); | ||
402 | + if (st_gdata == NULL) | ||
403 | + pr_err("error 1\n"); | ||
404 | + if (new_proto == NULL) | ||
405 | + pr_err("error 2\n"); | ||
406 | + if (new_proto->recv == NULL) | ||
407 | + pr_err("error 3\n"); | ||
408 | + if (new_proto->reg_complete_cb == NULL) | ||
409 | + pr_err("erro 4\n"); | ||
410 | return -1; | ||
411 | } | ||
412 | |||
413 | - if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) { | ||
414 | - pr_err("protocol %d not supported", new_proto->type); | ||
415 | + if (new_proto->chnl_id >= ST_MAX_CHANNELS) { | ||
416 | + pr_err("chnl_id %d not supported", new_proto->chnl_id); | ||
417 | return -EPROTONOSUPPORT; | ||
418 | } | ||
419 | |||
420 | - if (st_gdata->list[new_proto->type] != NULL) { | ||
421 | - pr_err("protocol %d already registered", new_proto->type); | ||
422 | + if (st_gdata->list[new_proto->chnl_id] != NULL) { | ||
423 | + pr_err("chnl_id %d already registered", new_proto->chnl_id); | ||
424 | return -EALREADY; | ||
425 | } | ||
426 | |||
427 | @@ -586,11 +482,11 @@ long st_register(struct st_proto_s *new_proto) | ||
428 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
429 | |||
430 | if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { | ||
431 | - pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type); | ||
432 | + pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); | ||
433 | /* fw download in progress */ | ||
434 | - st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); | ||
435 | + st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE); | ||
436 | |||
437 | - st_gdata->list[new_proto->type] = new_proto; | ||
438 | + add_channel_to_table(st_gdata, new_proto); | ||
439 | st_gdata->protos_registered++; | ||
440 | new_proto->write = st_write; | ||
441 | |||
442 | @@ -598,7 +494,7 @@ long st_register(struct st_proto_s *new_proto) | ||
443 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
444 | return -EINPROGRESS; | ||
445 | } else if (st_gdata->protos_registered == ST_EMPTY) { | ||
446 | - pr_info(" protocol list empty :%d ", new_proto->type); | ||
447 | + pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); | ||
448 | set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); | ||
449 | st_recv = st_kim_recv; | ||
450 | |||
451 | @@ -622,9 +518,9 @@ long st_register(struct st_proto_s *new_proto) | ||
452 | return -1; | ||
453 | } | ||
454 | |||
455 | - /* the protocol might require other gpios to be toggled | ||
456 | + /* the chnl_id might require other gpios to be toggled | ||
457 | */ | ||
458 | - st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); | ||
459 | + st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE); | ||
460 | |||
461 | clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); | ||
462 | st_recv = st_int_recv; | ||
463 | @@ -642,14 +538,14 @@ long st_register(struct st_proto_s *new_proto) | ||
464 | /* check for already registered once more, | ||
465 | * since the above check is old | ||
466 | */ | ||
467 | - if (st_gdata->list[new_proto->type] != NULL) { | ||
468 | + if (st_gdata->list[new_proto->chnl_id] != NULL) { | ||
469 | pr_err(" proto %d already registered ", | ||
470 | - new_proto->type); | ||
471 | + new_proto->chnl_id); | ||
472 | return -EALREADY; | ||
473 | } | ||
474 | |||
475 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
476 | - st_gdata->list[new_proto->type] = new_proto; | ||
477 | + add_channel_to_table(st_gdata, new_proto); | ||
478 | st_gdata->protos_registered++; | ||
479 | new_proto->write = st_write; | ||
480 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
481 | @@ -657,22 +553,7 @@ long st_register(struct st_proto_s *new_proto) | ||
482 | } | ||
483 | /* if fw is already downloaded & new stack registers protocol */ | ||
484 | else { | ||
485 | - switch (new_proto->type) { | ||
486 | - case ST_BT: | ||
487 | - /* do nothing */ | ||
488 | - break; | ||
489 | - case ST_FM: | ||
490 | - case ST_GPS: | ||
491 | - st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); | ||
492 | - break; | ||
493 | - case ST_MAX: | ||
494 | - default: | ||
495 | - pr_err("%d protocol not supported", | ||
496 | - new_proto->type); | ||
497 | - spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
498 | - return -EPROTONOSUPPORT; | ||
499 | - } | ||
500 | - st_gdata->list[new_proto->type] = new_proto; | ||
501 | + add_channel_to_table(st_gdata, new_proto); | ||
502 | st_gdata->protos_registered++; | ||
503 | new_proto->write = st_write; | ||
504 | |||
505 | @@ -680,48 +561,48 @@ long st_register(struct st_proto_s *new_proto) | ||
506 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
507 | return err; | ||
508 | } | ||
509 | - pr_debug("done %s(%d) ", __func__, new_proto->type); | ||
510 | + pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); | ||
511 | } | ||
512 | EXPORT_SYMBOL_GPL(st_register); | ||
513 | |||
514 | /* to unregister a protocol - | ||
515 | * to be called from protocol stack driver | ||
516 | */ | ||
517 | -long st_unregister(enum proto_type type) | ||
518 | +long st_unregister(struct st_proto_s *proto) | ||
519 | { | ||
520 | long err = 0; | ||
521 | unsigned long flags = 0; | ||
522 | struct st_data_s *st_gdata; | ||
523 | |||
524 | - pr_debug("%s: %d ", __func__, type); | ||
525 | + pr_debug("%s: %d ", __func__, proto->chnl_id); | ||
526 | |||
527 | st_kim_ref(&st_gdata, 0); | ||
528 | - if (type < ST_BT || type >= ST_MAX) { | ||
529 | - pr_err(" protocol %d not supported", type); | ||
530 | + if (proto->chnl_id >= ST_MAX_CHANNELS) { | ||
531 | + pr_err(" chnl_id %d not supported", proto->chnl_id); | ||
532 | return -EPROTONOSUPPORT; | ||
533 | } | ||
534 | |||
535 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
536 | |||
537 | - if (st_gdata->list[type] == NULL) { | ||
538 | - pr_err(" protocol %d not registered", type); | ||
539 | + if (st_gdata->list[proto->chnl_id] == NULL) { | ||
540 | + pr_err(" chnl_id %d not registered", proto->chnl_id); | ||
541 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
542 | return -EPROTONOSUPPORT; | ||
543 | } | ||
544 | |||
545 | st_gdata->protos_registered--; | ||
546 | - st_gdata->list[type] = NULL; | ||
547 | + remove_channel_from_table(st_gdata, proto); | ||
548 | |||
549 | /* kim ignores BT in the below function | ||
550 | * and handles the rest, BT is toggled | ||
551 | * only in kim_start and kim_stop | ||
552 | */ | ||
553 | - st_kim_chip_toggle(type, KIM_GPIO_INACTIVE); | ||
554 | + st_kim_chip_toggle(proto->chnl_id, KIM_GPIO_INACTIVE); | ||
555 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
556 | |||
557 | if ((st_gdata->protos_registered == ST_EMPTY) && | ||
558 | (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | ||
559 | - pr_info(" all protocols unregistered "); | ||
560 | + pr_info(" all chnl_ids unregistered "); | ||
561 | |||
562 | /* stop traffic on tty */ | ||
563 | if (st_gdata->tty) { | ||
564 | @@ -729,7 +610,7 @@ long st_unregister(enum proto_type type) | ||
565 | stop_tty(st_gdata->tty); | ||
566 | } | ||
567 | |||
568 | - /* all protocols now unregistered */ | ||
569 | + /* all chnl_ids now unregistered */ | ||
570 | st_kim_stop(st_gdata->kim_data); | ||
571 | /* disable ST LL */ | ||
572 | st_ll_disable(st_gdata); | ||
573 | @@ -745,7 +626,7 @@ long st_write(struct sk_buff *skb) | ||
574 | { | ||
575 | struct st_data_s *st_gdata; | ||
576 | #ifdef DEBUG | ||
577 | - enum proto_type protoid = ST_MAX; | ||
578 | + unsigned char chnl_id = ST_MAX_CHANNELS; | ||
579 | #endif | ||
580 | long len; | ||
581 | |||
582 | @@ -756,22 +637,10 @@ long st_write(struct sk_buff *skb) | ||
583 | return -1; | ||
584 | } | ||
585 | #ifdef DEBUG /* open-up skb to read the 1st byte */ | ||
586 | - switch (skb->data[0]) { | ||
587 | - case HCI_COMMAND_PKT: | ||
588 | - case HCI_ACLDATA_PKT: | ||
589 | - case HCI_SCODATA_PKT: | ||
590 | - protoid = ST_BT; | ||
591 | - break; | ||
592 | - case ST_FM_CH8_PKT: | ||
593 | - protoid = ST_FM; | ||
594 | - break; | ||
595 | - case 0x09: | ||
596 | - protoid = ST_GPS; | ||
597 | - break; | ||
598 | - } | ||
599 | - if (unlikely(st_gdata->list[protoid] == NULL)) { | ||
600 | - pr_err(" protocol %d not registered, and writing? ", | ||
601 | - protoid); | ||
602 | + chnl_id = skb->data[0]; | ||
603 | + if (unlikely(st_gdata->list[chnl_id] == NULL)) { | ||
604 | + pr_err(" chnl_id %d not registered, and writing? ", | ||
605 | + chnl_id); | ||
606 | return -1; | ||
607 | } | ||
608 | #endif | ||
609 | @@ -824,7 +693,7 @@ static int st_tty_open(struct tty_struct *tty) | ||
610 | |||
611 | static void st_tty_close(struct tty_struct *tty) | ||
612 | { | ||
613 | - unsigned char i = ST_MAX; | ||
614 | + unsigned char i = ST_MAX_CHANNELS; | ||
615 | unsigned long flags = 0; | ||
616 | struct st_data_s *st_gdata = tty->disc_data; | ||
617 | |||
618 | @@ -835,7 +704,7 @@ static void st_tty_close(struct tty_struct *tty) | ||
619 | * un-installed for some reason - what should be done ? | ||
620 | */ | ||
621 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
622 | - for (i = ST_BT; i < ST_MAX; i++) { | ||
623 | + for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { | ||
624 | if (st_gdata->list[i] != NULL) | ||
625 | pr_err("%d not un-registered", i); | ||
626 | st_gdata->list[i] = NULL; | ||
627 | @@ -869,7 +738,7 @@ static void st_tty_close(struct tty_struct *tty) | ||
628 | static void st_tty_receive(struct tty_struct *tty, const unsigned char *data, | ||
629 | char *tty_flags, int count) | ||
630 | { | ||
631 | - | ||
632 | +#define VERBOSE | ||
633 | #ifdef VERBOSE | ||
634 | print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, | ||
635 | 16, 1, data, count, 0); | ||
636 | diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c | ||
637 | index 73b6c8b..707c858 100644 | ||
638 | --- a/drivers/misc/ti-st/st_kim.c | ||
639 | +++ b/drivers/misc/ti-st/st_kim.c | ||
640 | @@ -32,11 +32,7 @@ | ||
641 | #include <linux/sched.h> | ||
642 | #include <linux/rfkill.h> | ||
643 | |||
644 | -/* understand BT events for fw response */ | ||
645 | -#include <net/bluetooth/bluetooth.h> | ||
646 | -#include <net/bluetooth/hci_core.h> | ||
647 | -#include <net/bluetooth/hci.h> | ||
648 | - | ||
649 | +#include <linux/skbuff.h> | ||
650 | #include <linux/ti_wilink_st.h> | ||
651 | |||
652 | |||
653 | @@ -134,7 +130,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len) | ||
654 | /* Packet header has non-zero payload length and | ||
655 | * we have enough space in created skb. Lets read | ||
656 | * payload data */ | ||
657 | - kim_gdata->rx_state = ST_BT_W4_DATA; | ||
658 | + kim_gdata->rx_state = ST_W4_DATA; | ||
659 | kim_gdata->rx_count = len; | ||
660 | return len; | ||
661 | } | ||
662 | @@ -158,8 +154,8 @@ void kim_int_recv(struct kim_data_s *kim_gdata, | ||
663 | const unsigned char *data, long count) | ||
664 | { | ||
665 | const unsigned char *ptr; | ||
666 | - struct hci_event_hdr *eh; | ||
667 | int len = 0, type = 0; | ||
668 | + unsigned char *plen; | ||
669 | |||
670 | pr_debug("%s", __func__); | ||
671 | /* Decode received bytes here */ | ||
672 | @@ -183,29 +179,27 @@ void kim_int_recv(struct kim_data_s *kim_gdata, | ||
673 | /* Check ST RX state machine , where are we? */ | ||
674 | switch (kim_gdata->rx_state) { | ||
675 | /* Waiting for complete packet ? */ | ||
676 | - case ST_BT_W4_DATA: | ||
677 | + case ST_W4_DATA: | ||
678 | pr_debug("Complete pkt received"); | ||
679 | validate_firmware_response(kim_gdata); | ||
680 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
681 | kim_gdata->rx_skb = NULL; | ||
682 | continue; | ||
683 | /* Waiting for Bluetooth event header ? */ | ||
684 | - case ST_BT_W4_EVENT_HDR: | ||
685 | - eh = (struct hci_event_hdr *)kim_gdata-> | ||
686 | - rx_skb->data; | ||
687 | - pr_debug("Event header: evt 0x%2.2x" | ||
688 | - "plen %d", eh->evt, eh->plen); | ||
689 | - kim_check_data_len(kim_gdata, eh->plen); | ||
690 | + case ST_W4_HEADER: | ||
691 | + plen = | ||
692 | + (unsigned char *)&kim_gdata->rx_skb->data[1]; | ||
693 | + pr_debug("event hdr: plen 0x%02x\n", *plen); | ||
694 | + kim_check_data_len(kim_gdata, *plen); | ||
695 | continue; | ||
696 | } /* end of switch */ | ||
697 | } /* end of if rx_state */ | ||
698 | switch (*ptr) { | ||
699 | /* Bluetooth event packet? */ | ||
700 | - case HCI_EVENT_PKT: | ||
701 | - pr_info("Event packet"); | ||
702 | - kim_gdata->rx_state = ST_BT_W4_EVENT_HDR; | ||
703 | - kim_gdata->rx_count = HCI_EVENT_HDR_SIZE; | ||
704 | - type = HCI_EVENT_PKT; | ||
705 | + case 0x04: | ||
706 | + kim_gdata->rx_state = ST_W4_HEADER; | ||
707 | + kim_gdata->rx_count = 2; | ||
708 | + type = *ptr; | ||
709 | break; | ||
710 | default: | ||
711 | pr_info("unknown packet"); | ||
712 | @@ -216,16 +210,18 @@ void kim_int_recv(struct kim_data_s *kim_gdata, | ||
713 | ptr++; | ||
714 | count--; | ||
715 | kim_gdata->rx_skb = | ||
716 | - bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); | ||
717 | + alloc_skb(1024+8, GFP_ATOMIC); | ||
718 | if (!kim_gdata->rx_skb) { | ||
719 | pr_err("can't allocate mem for new packet"); | ||
720 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
721 | kim_gdata->rx_count = 0; | ||
722 | return; | ||
723 | } | ||
724 | - bt_cb(kim_gdata->rx_skb)->pkt_type = type; | ||
725 | + skb_reserve(kim_gdata->rx_skb, 8); | ||
726 | + kim_gdata->rx_skb->cb[0] = 4; | ||
727 | + kim_gdata->rx_skb->cb[1] = 0; | ||
728 | + | ||
729 | } | ||
730 | - pr_info("done %s", __func__); | ||
731 | return; | ||
732 | } | ||
733 | |||
734 | @@ -398,7 +394,7 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state) | ||
735 | gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW); | ||
736 | break; | ||
737 | |||
738 | - case ST_MAX: | ||
739 | + case ST_MAX_CHANNELS: | ||
740 | default: | ||
741 | break; | ||
742 | } | ||
743 | @@ -416,7 +412,6 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count) | ||
744 | struct st_data_s *st_gdata = (struct st_data_s *)disc_data; | ||
745 | struct kim_data_s *kim_gdata = st_gdata->kim_data; | ||
746 | |||
747 | - pr_info(" %s ", __func__); | ||
748 | /* copy to local buffer */ | ||
749 | if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) { | ||
750 | /* must be the read_ver_cmd */ | ||
751 | @@ -578,7 +573,7 @@ static int kim_toggle_radio(void *data, bool blocked) | ||
752 | else | ||
753 | st_kim_chip_toggle(type, KIM_GPIO_ACTIVE); | ||
754 | break; | ||
755 | - case ST_MAX: | ||
756 | + case ST_MAX_CHANNELS: | ||
757 | pr_err(" wrong proto type "); | ||
758 | break; | ||
759 | } | ||
760 | @@ -664,12 +659,13 @@ static int kim_probe(struct platform_device *pdev) | ||
761 | /* refer to itself */ | ||
762 | kim_gdata->core_data->kim_data = kim_gdata; | ||
763 | |||
764 | - for (proto = 0; proto < ST_MAX; proto++) { | ||
765 | + for (proto = 0; proto < ST_MAX_CHANNELS; proto++) { | ||
766 | kim_gdata->gpios[proto] = gpios[proto]; | ||
767 | pr_info(" %ld gpio to be requested", gpios[proto]); | ||
768 | } | ||
769 | |||
770 | - for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) { | ||
771 | + for (proto = 0; (proto < ST_MAX_CHANNELS) | ||
772 | + && (gpios[proto] != -1); proto++) { | ||
773 | /* Claim the Bluetooth/FM/GPIO | ||
774 | * nShutdown gpio from the system | ||
775 | */ | ||
776 | @@ -704,7 +700,8 @@ static int kim_probe(struct platform_device *pdev) | ||
777 | init_completion(&kim_gdata->kim_rcvd); | ||
778 | init_completion(&kim_gdata->ldisc_installed); | ||
779 | |||
780 | - for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) { | ||
781 | + for (proto = 0; (proto < ST_MAX_CHANNELS) | ||
782 | + && (gpios[proto] != -1); proto++) { | ||
783 | /* TODO: should all types be rfkill_type_bt ? */ | ||
784 | kim_gdata->rf_protos[proto] = proto; | ||
785 | kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto], | ||
786 | @@ -752,7 +749,8 @@ static int kim_remove(struct platform_device *pdev) | ||
787 | |||
788 | kim_gdata = dev_get_drvdata(&pdev->dev); | ||
789 | |||
790 | - for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) { | ||
791 | + for (proto = 0; (proto < ST_MAX_CHANNELS) | ||
792 | + && (gpios[proto] != -1); proto++) { | ||
793 | /* Claim the Bluetooth/FM/GPIO | ||
794 | * nShutdown gpio from the system | ||
795 | */ | ||
796 | diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h | ||
797 | index 4c7be22..1674ca7 100644 | ||
798 | --- a/include/linux/ti_wilink_st.h | ||
799 | +++ b/include/linux/ti_wilink_st.h | ||
800 | @@ -42,7 +42,7 @@ enum proto_type { | ||
801 | ST_BT, | ||
802 | ST_FM, | ||
803 | ST_GPS, | ||
804 | - ST_MAX, | ||
805 | + ST_MAX_CHANNELS = 16, | ||
806 | }; | ||
807 | |||
808 | /** | ||
809 | @@ -62,6 +62,17 @@ enum proto_type { | ||
810 | * @priv_data: privdate data holder for the protocol drivers, sent | ||
811 | * from the protocol drivers during registration, and sent back on | ||
812 | * reg_complete_cb and recv. | ||
813 | + * @chnl_id: channel id the protocol driver is interested in, the channel | ||
814 | + * id is nothing but the 1st byte of the packet in UART frame. | ||
815 | + * @max_frame_size: size of the largest frame the protocol can receive. | ||
816 | + * @hdr_len: length of the header structure of the protocol. | ||
817 | + * @offset_len_in_hdr: this provides the offset of the length field in the | ||
818 | + * header structure of the protocol header, to assist ST to know | ||
819 | + * how much to receive, if the data is split across UART frames. | ||
820 | + * @len_size: whether the length field inside the header is 2 bytes | ||
821 | + * or 1 byte. | ||
822 | + * @reserve: the number of bytes ST needs to reserve in the skb being | ||
823 | + * prepared for the protocol driver. | ||
824 | */ | ||
825 | struct st_proto_s { | ||
826 | enum proto_type type; | ||
827 | @@ -70,10 +81,17 @@ struct st_proto_s { | ||
828 | void (*reg_complete_cb) (void *, char data); | ||
829 | long (*write) (struct sk_buff *skb); | ||
830 | void *priv_data; | ||
831 | + | ||
832 | + unsigned char chnl_id; | ||
833 | + unsigned short max_frame_size; | ||
834 | + unsigned char hdr_len; | ||
835 | + unsigned char offset_len_in_hdr; | ||
836 | + unsigned char len_size; | ||
837 | + unsigned char reserve; | ||
838 | }; | ||
839 | |||
840 | extern long st_register(struct st_proto_s *); | ||
841 | -extern long st_unregister(enum proto_type); | ||
842 | +extern long st_unregister(struct st_proto_s *); | ||
843 | |||
844 | |||
845 | /* | ||
846 | @@ -114,6 +132,7 @@ extern long st_unregister(enum proto_type); | ||
847 | * @rx_skb: the skb where all data for a protocol gets accumulated, | ||
848 | * since tty might not call receive when a complete event packet | ||
849 | * is received, the states, count and the skb needs to be maintained. | ||
850 | + * @rx_chnl: the channel ID for which the data is getting accumalated for. | ||
851 | * @txq: the list of skbs which needs to be sent onto the TTY. | ||
852 | * @tx_waitq: if the chip is not in AWAKE state, the skbs needs to be queued | ||
853 | * up in here, PM(WAKEUP_IND) data needs to be sent and then the skbs | ||
854 | @@ -135,10 +154,11 @@ struct st_data_s { | ||
855 | #define ST_TX_SENDING 1 | ||
856 | #define ST_TX_WAKEUP 2 | ||
857 | unsigned long tx_state; | ||
858 | - struct st_proto_s *list[ST_MAX]; | ||
859 | + struct st_proto_s *list[ST_MAX_CHANNELS]; | ||
860 | unsigned long rx_state; | ||
861 | unsigned long rx_count; | ||
862 | struct sk_buff *rx_skb; | ||
863 | + unsigned char rx_chnl; | ||
864 | struct sk_buff_head txq, tx_waitq; | ||
865 | spinlock_t lock; | ||
866 | unsigned char protos_registered; | ||
867 | @@ -243,12 +263,12 @@ struct kim_data_s { | ||
868 | struct completion kim_rcvd, ldisc_installed; | ||
869 | char resp_buffer[30]; | ||
870 | const struct firmware *fw_entry; | ||
871 | - long gpios[ST_MAX]; | ||
872 | + long gpios[ST_MAX_CHANNELS]; | ||
873 | unsigned long rx_state; | ||
874 | unsigned long rx_count; | ||
875 | struct sk_buff *rx_skb; | ||
876 | - struct rfkill *rfkill[ST_MAX]; | ||
877 | - enum proto_type rf_protos[ST_MAX]; | ||
878 | + struct rfkill *rfkill[ST_MAX_CHANNELS]; | ||
879 | + enum proto_type rf_protos[ST_MAX_CHANNELS]; | ||
880 | struct st_data_s *core_data; | ||
881 | struct chip_version version; | ||
882 | }; | ||
883 | @@ -338,12 +358,8 @@ struct hci_command { | ||
884 | |||
885 | /* ST LL receiver states */ | ||
886 | #define ST_W4_PACKET_TYPE 0 | ||
887 | -#define ST_BT_W4_EVENT_HDR 1 | ||
888 | -#define ST_BT_W4_ACL_HDR 2 | ||
889 | -#define ST_BT_W4_SCO_HDR 3 | ||
890 | -#define ST_BT_W4_DATA 4 | ||
891 | -#define ST_FM_W4_EVENT_HDR 5 | ||
892 | -#define ST_GPS_W4_EVENT_HDR 6 | ||
893 | +#define ST_W4_HEADER 1 | ||
894 | +#define ST_W4_DATA 2 | ||
895 | |||
896 | /* ST LL state machines */ | ||
897 | #define ST_LL_ASLEEP 0 | ||
898 | -- | ||
899 | 1.6.6.1 | ||
900 | |||