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#include <linux/export.h>
34
35#include <asm/byteorder.h>
36
37#include <net/irda/irda.h>
38#include <net/irda/parameters.h>
39#include <net/irda/qos.h>
40#include <net/irda/irlap.h>
41#include <net/irda/irlap_frame.h>
42
43
44
45
46
47
48
49int sysctl_max_baud_rate = 16000000;
50
51
52
53
54
55
56int sysctl_max_noreply_time = 12;
57
58
59
60
61
62
63
64
65unsigned int sysctl_min_tx_turn_time = 10;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80unsigned int sysctl_max_tx_data_size = 2042;
81
82
83
84
85
86unsigned int sysctl_max_tx_window = 7;
87
88static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
89static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
90 int get);
91static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
92 int get);
93static int irlap_param_data_size(void *instance, irda_param_t *param, int get);
94static int irlap_param_window_size(void *instance, irda_param_t *param,
95 int get);
96static int irlap_param_additional_bofs(void *instance, irda_param_t *parm,
97 int get);
98static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
99 int get);
100
101#ifndef CONFIG_IRDA_DYNAMIC_WINDOW
102static __u32 irlap_requested_line_capacity(struct qos_info *qos);
103#endif
104
105static __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 };
106static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
107 1152000, 4000000, 16000000 };
108static __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 };
109static __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 };
110static __u32 max_turn_times[] = { 500, 250, 100, 50 };
111static __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 };
112
113static __u32 max_line_capacities[10][4] = {
114
115 { 100, 0, 0, 0 },
116 { 400, 0, 0, 0 },
117 { 800, 0, 0, 0 },
118 { 1600, 0, 0, 0 },
119 { 2360, 0, 0, 0 },
120 { 4800, 2400, 960, 480 },
121 { 28800, 11520, 5760, 2880 },
122 { 57600, 28800, 11520, 5760 },
123 { 200000, 100000, 40000, 20000 },
124 { 800000, 400000, 160000, 80000 },
125};
126
127static pi_minor_info_t pi_minor_call_table_type_0[] = {
128 { NULL, 0 },
129{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN },
130 { NULL, 0 },
131 { NULL, 0 },
132 { NULL, 0 },
133 { NULL, 0 },
134 { NULL, 0 },
135 { NULL, 0 },
136{ irlap_param_link_disconnect, PV_INT_8_BITS }
137};
138
139static pi_minor_info_t pi_minor_call_table_type_1[] = {
140 { NULL, 0 },
141 { NULL, 0 },
142{ irlap_param_max_turn_time, PV_INT_8_BITS },
143{ irlap_param_data_size, PV_INT_8_BITS },
144{ irlap_param_window_size, PV_INT_8_BITS },
145{ irlap_param_additional_bofs, PV_INT_8_BITS },
146{ irlap_param_min_turn_time, PV_INT_8_BITS },
147};
148
149static pi_major_info_t pi_major_call_table[] = {
150 { pi_minor_call_table_type_0, 9 },
151 { pi_minor_call_table_type_1, 7 },
152};
153
154static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 };
155
156
157
158
159
160
161
162
163
164
165
166
167static inline int value_index(__u32 value, __u32 *array, int size)
168{
169 int i;
170
171 for (i=0; i < size; i++)
172 if (array[i] == value)
173 break;
174 return i;
175}
176
177
178
179
180
181
182
183static inline __u32 index_value(int index, __u32 *array)
184{
185 return array[index];
186}
187
188
189
190
191
192
193
194static int msb_index (__u16 word)
195{
196 __u16 msb = 0x8000;
197 int index = 15;
198
199
200
201
202
203
204 if (word == 0) {
205 IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
206 __func__);
207
208 word = 0x1;
209 }
210
211 while (msb) {
212 if (word & msb)
213 break;
214 msb >>=1;
215 index--;
216 }
217 return index;
218}
219
220
221
222
223
224
225static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field)
226{
227 int i;
228 __u16 mask = 0x1;
229 __u16 result = 0x0;
230
231 for (i=0; i < size; i++) {
232
233 result |= mask;
234 mask <<= 1;
235
236 if (array[i] >= value)
237 break;
238 }
239
240 if(i >= size)
241 i = size - 1;
242 *field = result;
243 return i;
244}
245
246
247
248
249
250
251static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field)
252{
253 int i;
254 __u16 mask = 0x1;
255 __u16 result = 0x0;
256
257 for (i=0; i < size; i++) {
258
259 if (array[i] <= value)
260 break;
261
262 mask <<= 1;
263 }
264
265 result |= mask;
266
267 if(i >= size)
268 i = size - 1;
269 *field = result;
270 return i;
271}
272
273
274
275
276
277
278
279
280
281void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
282{
283 IRDA_ASSERT(qos != NULL, return;);
284 IRDA_ASSERT(new != NULL, return;);
285
286
287 qos->baud_rate.bits &= new->baud_rate.bits;
288 qos->window_size.bits &= new->window_size.bits;
289 qos->min_turn_time.bits &= new->min_turn_time.bits;
290 qos->max_turn_time.bits &= new->max_turn_time.bits;
291 qos->data_size.bits &= new->data_size.bits;
292 qos->link_disc_time.bits &= new->link_disc_time.bits;
293 qos->additional_bofs.bits &= new->additional_bofs.bits;
294
295 irda_qos_bits_to_value(qos);
296}
297
298
299
300
301
302
303
304
305void irda_init_max_qos_capabilies(struct qos_info *qos)
306{
307 int i;
308
309
310
311
312
313
314
315 i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10,
316 &qos->baud_rate.bits);
317 sysctl_max_baud_rate = index_value(i, baud_rates);
318
319
320 i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8,
321 &qos->link_disc_time.bits);
322 sysctl_max_noreply_time = index_value(i, link_disc_times);
323
324
325 qos->baud_rate.bits &= 0x03ff;
326
327 qos->window_size.bits = 0x7f;
328 qos->min_turn_time.bits = 0xff;
329 qos->max_turn_time.bits = 0x0f;
330 qos->data_size.bits = 0x3f;
331 qos->link_disc_time.bits &= 0xff;
332 qos->additional_bofs.bits = 0xff;
333}
334EXPORT_SYMBOL(irda_init_max_qos_capabilies);
335
336
337
338
339
340
341
342static void irlap_adjust_qos_settings(struct qos_info *qos)
343{
344 __u32 line_capacity;
345 int index;
346
347 IRDA_DEBUG(2, "%s()\n", __func__);
348
349
350
351
352
353 if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
354 int i;
355
356 IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
357 __func__, sysctl_min_tx_turn_time);
358
359
360 i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
361 8, &qos->min_turn_time.bits);
362 sysctl_min_tx_turn_time = index_value(i, min_turn_times);
363 qos->min_turn_time.value = sysctl_min_tx_turn_time;
364 }
365
366
367
368
369
370 if ((qos->baud_rate.value < 115200) &&
371 (qos->max_turn_time.value < 500))
372 {
373 IRDA_DEBUG(0,
374 "%s(), adjusting max turn time from %d to 500 ms\n",
375 __func__, qos->max_turn_time.value);
376 qos->max_turn_time.value = 500;
377 }
378
379
380
381
382
383 index = value_index(qos->data_size.value, data_sizes, 6);
384 line_capacity = irlap_max_line_capacity(qos->baud_rate.value,
385 qos->max_turn_time.value);
386
387#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
388 while ((qos->data_size.value > line_capacity) && (index > 0)) {
389 qos->data_size.value = data_sizes[index--];
390 IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
391 __func__, qos->data_size.value);
392 }
393#else
394 while (irlap_requested_line_capacity(qos) > line_capacity) {
395 IRDA_ASSERT(index != 0, return;);
396
397
398 if (qos->window_size.value > 1) {
399 qos->window_size.value--;
400 IRDA_DEBUG(2, "%s(), reducing window size to %d\n",
401 __func__, qos->window_size.value);
402 } else if (index > 1) {
403 qos->data_size.value = data_sizes[index--];
404 IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
405 __func__, qos->data_size.value);
406 } else {
407 IRDA_WARNING("%s(), nothing more we can do!\n",
408 __func__);
409 }
410 }
411#endif
412
413
414
415 if (qos->data_size.value > sysctl_max_tx_data_size)
416
417 qos->data_size.value = sysctl_max_tx_data_size;
418
419
420
421 if (qos->window_size.value > sysctl_max_tx_window)
422 qos->window_size.value = sysctl_max_tx_window;
423}
424
425
426
427
428
429
430
431
432int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb)
433{
434 int ret;
435
436 ret = irda_param_extract_all(self, skb->data, skb->len,
437 &irlap_param_info);
438
439
440 irda_qos_bits_to_value(&self->qos_tx);
441 irda_qos_bits_to_value(&self->qos_rx);
442
443 irlap_adjust_qos_settings(&self->qos_tx);
444
445 IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n",
446 self->qos_tx.baud_rate.value);
447 IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
448 self->qos_tx.data_size.value);
449 IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n",
450 self->qos_tx.window_size.value);
451 IRDA_DEBUG(2, "Setting XBOFS to %d\n",
452 self->qos_tx.additional_bofs.value);
453 IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
454 self->qos_tx.max_turn_time.value);
455 IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
456 self->qos_tx.min_turn_time.value);
457 IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n",
458 self->qos_tx.link_disc_time.value);
459 return ret;
460}
461
462
463
464
465
466
467
468int irlap_insert_qos_negotiation_params(struct irlap_cb *self,
469 struct sk_buff *skb)
470{
471 int ret;
472
473
474 ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb),
475 skb_tailroom(skb), &irlap_param_info);
476 if (ret < 0)
477 return ret;
478 skb_put(skb, ret);
479
480
481 ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb),
482 skb_tailroom(skb), &irlap_param_info);
483 if (ret < 0)
484 return ret;
485 skb_put(skb, ret);
486
487
488 ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb),
489 skb_tailroom(skb), &irlap_param_info);
490 if (ret < 0)
491 return ret;
492 skb_put(skb, ret);
493
494
495 ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb),
496 skb_tailroom(skb), &irlap_param_info);
497 if (ret < 0)
498 return ret;
499 skb_put(skb, ret);
500
501
502 ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb),
503 skb_tailroom(skb), &irlap_param_info);
504 if (ret < 0)
505 return ret;
506 skb_put(skb, ret);
507
508
509 ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb),
510 skb_tailroom(skb), &irlap_param_info);
511 if (ret < 0)
512 return ret;
513 skb_put(skb, ret);
514
515
516 ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb),
517 skb_tailroom(skb), &irlap_param_info);
518 if (ret < 0)
519 return ret;
520 skb_put(skb, ret);
521
522 return 0;
523}
524
525
526
527
528
529
530
531static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get)
532{
533 __u16 final;
534
535 struct irlap_cb *self = (struct irlap_cb *) instance;
536
537 IRDA_ASSERT(self != NULL, return -1;);
538 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
539
540 if (get) {
541 param->pv.i = self->qos_rx.baud_rate.bits;
542 IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n",
543 __func__, param->pv.i);
544 } else {
545
546
547
548
549 IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", (__u16) param->pv.i);
550 final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits;
551
552 IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final);
553 self->qos_tx.baud_rate.bits = final;
554 self->qos_rx.baud_rate.bits = final;
555 }
556
557 return 0;
558}
559
560
561
562
563
564
565
566static int irlap_param_link_disconnect(void *instance, irda_param_t *param,
567 int get)
568{
569 __u16 final;
570
571 struct irlap_cb *self = (struct irlap_cb *) instance;
572
573 IRDA_ASSERT(self != NULL, return -1;);
574 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
575
576 if (get)
577 param->pv.i = self->qos_rx.link_disc_time.bits;
578 else {
579
580
581
582
583 IRDA_DEBUG(2, "LINK_DISC: %02x\n", (__u8) param->pv.i);
584 final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits;
585
586 IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final);
587 self->qos_tx.link_disc_time.bits = final;
588 self->qos_rx.link_disc_time.bits = final;
589 }
590 return 0;
591}
592
593
594
595
596
597
598
599
600static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
601 int get)
602{
603 struct irlap_cb *self = (struct irlap_cb *) instance;
604
605 IRDA_ASSERT(self != NULL, return -1;);
606 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
607
608 if (get)
609 param->pv.i = self->qos_rx.max_turn_time.bits;
610 else
611 self->qos_tx.max_turn_time.bits = (__u8) param->pv.i;
612
613 return 0;
614}
615
616
617
618
619
620
621
622
623static int irlap_param_data_size(void *instance, irda_param_t *param, int get)
624{
625 struct irlap_cb *self = (struct irlap_cb *) instance;
626
627 IRDA_ASSERT(self != NULL, return -1;);
628 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
629
630 if (get)
631 param->pv.i = self->qos_rx.data_size.bits;
632 else
633 self->qos_tx.data_size.bits = (__u8) param->pv.i;
634
635 return 0;
636}
637
638
639
640
641
642
643
644
645static int irlap_param_window_size(void *instance, irda_param_t *param,
646 int get)
647{
648 struct irlap_cb *self = (struct irlap_cb *) instance;
649
650 IRDA_ASSERT(self != NULL, return -1;);
651 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
652
653 if (get)
654 param->pv.i = self->qos_rx.window_size.bits;
655 else
656 self->qos_tx.window_size.bits = (__u8) param->pv.i;
657
658 return 0;
659}
660
661
662
663
664
665
666
667static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get)
668{
669 struct irlap_cb *self = (struct irlap_cb *) instance;
670
671 IRDA_ASSERT(self != NULL, return -1;);
672 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
673
674 if (get)
675 param->pv.i = self->qos_rx.additional_bofs.bits;
676 else
677 self->qos_tx.additional_bofs.bits = (__u8) param->pv.i;
678
679 return 0;
680}
681
682
683
684
685
686
687
688static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
689 int get)
690{
691 struct irlap_cb *self = (struct irlap_cb *) instance;
692
693 IRDA_ASSERT(self != NULL, return -1;);
694 IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
695
696 if (get)
697 param->pv.i = self->qos_rx.min_turn_time.bits;
698 else
699 self->qos_tx.min_turn_time.bits = (__u8) param->pv.i;
700
701 return 0;
702}
703
704
705
706
707
708
709
710__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
711{
712 __u32 line_capacity;
713 int i,j;
714
715 IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n",
716 __func__, speed, max_turn_time);
717
718 i = value_index(speed, baud_rates, 10);
719 j = value_index(max_turn_time, max_turn_times, 4);
720
721 IRDA_ASSERT(((i >=0) && (i <10)), return 0;);
722 IRDA_ASSERT(((j >=0) && (j <4)), return 0;);
723
724 line_capacity = max_line_capacities[i][j];
725
726 IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n",
727 __func__, line_capacity);
728
729 return line_capacity;
730}
731
732#ifndef CONFIG_IRDA_DYNAMIC_WINDOW
733static __u32 irlap_requested_line_capacity(struct qos_info *qos)
734{
735 __u32 line_capacity;
736
737 line_capacity = qos->window_size.value *
738 (qos->data_size.value + 6 + qos->additional_bofs.value) +
739 irlap_min_turn_time_in_bytes(qos->baud_rate.value,
740 qos->min_turn_time.value);
741
742 IRDA_DEBUG(2, "%s(), requested line capacity=%d\n",
743 __func__, line_capacity);
744
745 return line_capacity;
746}
747#endif
748
749void irda_qos_bits_to_value(struct qos_info *qos)
750{
751 int index;
752
753 IRDA_ASSERT(qos != NULL, return;);
754
755 index = msb_index(qos->baud_rate.bits);
756 qos->baud_rate.value = baud_rates[index];
757
758 index = msb_index(qos->data_size.bits);
759 qos->data_size.value = data_sizes[index];
760
761 index = msb_index(qos->window_size.bits);
762 qos->window_size.value = index+1;
763
764 index = msb_index(qos->min_turn_time.bits);
765 qos->min_turn_time.value = min_turn_times[index];
766
767 index = msb_index(qos->max_turn_time.bits);
768 qos->max_turn_time.value = max_turn_times[index];
769
770 index = msb_index(qos->link_disc_time.bits);
771 qos->link_disc_time.value = link_disc_times[index];
772
773 index = msb_index(qos->additional_bofs.bits);
774 qos->additional_bofs.value = add_bofs[index];
775}
776EXPORT_SYMBOL(irda_qos_bits_to_value);
777