00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <linux/config.h>
00033 #include <asm/byteorder.h>
00034
00035 #include <net/irda/irda.h>
00036 #include <net/irda/parameters.h>
00037 #include <net/irda/qos.h>
00038 #include <net/irda/irlap.h>
00039 #ifdef CONFIG_IRDA_COMPRESSION
00040 #include <net/irda/irlap_comp.h>
00041 #include "../../drivers/net/zlib.h"
00042
00043 #define CI_BZIP2 27
00044 #endif
00045
00046 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
00047 static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
00048 int get);
00049 static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
00050 int get);
00051 static int irlap_param_data_size(void *instance, irda_param_t *param, int get);
00052 static int irlap_param_window_size(void *instance, irda_param_t *param,
00053 int get);
00054 static int irlap_param_additional_bofs(void *instance, irda_param_t *parm,
00055 int get);
00056 static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
00057 int get);
00058
00059 __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 };
00060 __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
00061 1152000, 4000000, 16000000 };
00062 __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 };
00063 __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 };
00064 __u32 max_turn_times[] = { 500, 250, 100, 50 };
00065 __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 };
00066
00067 #ifdef CONFIG_IRDA_COMPRESSION
00068 __u32 compressions[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
00069 #endif
00070
00071 __u32 max_line_capacities[10][4] = {
00072
00073 { 100, 0, 0, 0 },
00074 { 400, 0, 0, 0 },
00075 { 800, 0, 0, 0 },
00076 { 1600, 0, 0, 0 },
00077 { 2360, 0, 0, 0 },
00078 { 4800, 2400, 960, 480 },
00079 { 28800, 11520, 5760, 2880 },
00080 { 57600, 28800, 11520, 5760 },
00081 { 200000, 100000, 40000, 20000 },
00082 { 800000, 400000, 160000, 80000 },
00083 };
00084
00085 static pi_minor_info_t pi_minor_call_table_type_0[] = {
00086 { NULL, 0 },
00087 { irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN },
00088 { NULL, 0 },
00089 { NULL, 0 },
00090 { NULL, 0 },
00091 { NULL, 0 },
00092 { NULL, 0 },
00093 { NULL, 0 },
00094 { irlap_param_link_disconnect, PV_INT_8_BITS }
00095 };
00096
00097 static pi_minor_info_t pi_minor_call_table_type_1[] = {
00098 { NULL, 0 },
00099 { NULL, 0 },
00100 { irlap_param_max_turn_time, PV_INT_8_BITS },
00101 { irlap_param_data_size, PV_INT_8_BITS },
00102 { irlap_param_window_size, PV_INT_8_BITS },
00103 { irlap_param_additional_bofs, PV_INT_8_BITS },
00104 { irlap_param_min_turn_time, PV_INT_8_BITS },
00105 };
00106
00107 static pi_major_info_t pi_major_call_table[] = {
00108 { pi_minor_call_table_type_0, 9 },
00109 { pi_minor_call_table_type_1, 7 },
00110 };
00111
00112 static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 };
00113
00114
00115
00116
00117
00118
00119
00120 void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
00121 {
00122 ASSERT(qos != NULL, return;);
00123 ASSERT(new != NULL, return;);
00124
00125
00126 qos->baud_rate.bits &= new->baud_rate.bits;
00127 qos->window_size.bits &= new->window_size.bits;
00128 qos->min_turn_time.bits &= new->min_turn_time.bits;
00129 qos->max_turn_time.bits &= new->max_turn_time.bits;
00130 qos->data_size.bits &= new->data_size.bits;
00131 qos->link_disc_time.bits &= new->link_disc_time.bits;
00132 qos->additional_bofs.bits &= new->additional_bofs.bits;
00133
00134 #ifdef CONFIG_IRDA_COMPRESSION
00135 qos->compression.bits &= new->compression.bits;
00136 #endif
00137
00138 irda_qos_bits_to_value(qos);
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148 void irda_init_max_qos_capabilies(struct qos_info *qos)
00149 {
00150
00151
00152
00153
00154
00155
00156 qos->baud_rate.bits = 0x01ff;
00157
00158 qos->window_size.bits = 0x7f;
00159 qos->min_turn_time.bits = 0xff;
00160 qos->max_turn_time.bits = 0x0f;
00161 qos->data_size.bits = 0x3f;
00162 qos->link_disc_time.bits = 0xff;
00163 qos->additional_bofs.bits = 0xff;
00164
00165 #ifdef CONFIG_IRDA_COMPRESSION
00166 qos->compression.bits = 0x03;
00167 #endif
00168 }
00169
00170
00171
00172
00173
00174
00175
00176 void irlap_adjust_qos_settings(struct qos_info *qos)
00177 {
00178 __u32 line_capacity;
00179 int index;
00180
00181 IRDA_DEBUG(2, __FUNCTION__ "()\n");
00182
00183
00184
00185
00186
00187 if ((qos->baud_rate.value < 115200) &&
00188 (qos->max_turn_time.value < 500))
00189 {
00190 IRDA_DEBUG(0, __FUNCTION__
00191 "(), adjusting max turn time from %d to 500 ms\n",
00192 qos->max_turn_time.value);
00193 qos->max_turn_time.value = 500;
00194 }
00195
00196
00197
00198
00199
00200 index = value_index(qos->data_size.value, data_sizes);
00201 line_capacity = irlap_max_line_capacity(qos->baud_rate.value,
00202 qos->max_turn_time.value);
00203
00204 #ifdef CONFIG_IRDA_DYNAMIC_WINDOW
00205 while ((qos->data_size.value > line_capacity) && (index > 0)) {
00206 qos->data_size.value = data_sizes[index--];
00207 IRDA_DEBUG(2, __FUNCTION__
00208 "(), redusing data size to %d\n",
00209 qos->data_size.value);
00210 }
00211 #else
00212 while (irlap_requested_line_capacity(qos) > line_capacity) {
00213 ASSERT(index != 0, return;);
00214
00215
00216 if (qos->window_size.value > 1) {
00217 qos->window_size.value--;
00218 IRDA_DEBUG(2, __FUNCTION__
00219 "(), redusing window size to %d\n",
00220 qos->window_size.value);
00221 } else if (index > 1) {
00222 qos->data_size.value = data_sizes[index--];
00223 IRDA_DEBUG(2, __FUNCTION__
00224 "(), redusing data size to %d\n",
00225 qos->data_size.value);
00226 } else {
00227 WARNING(__FUNCTION__ "(), nothing more we can do!\n");
00228 }
00229 }
00230 #endif CONFIG_IRDA_DYNAMIC_WINDOW
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240 int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb)
00241 {
00242 int ret;
00243 #ifdef CONFIG_IRDA_COMPRESSION
00244 int comp_seen = FALSE;
00245 #endif
00246 ret = irda_param_extract_all(self, skb->data, skb->len,
00247 &irlap_param_info);
00248
00249 #ifdef CONFIG_IRDA_COMPRESSION
00250 if (!comp_seen) {
00251 IRDA_DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n");
00252 self->qos_tx.compression.bits = 0x00;
00253 self->qos_rx.compression.bits = 0x00;
00254 }
00255 #endif
00256
00257
00258 irda_qos_bits_to_value(&self->qos_tx);
00259 irda_qos_bits_to_value(&self->qos_rx);
00260
00261 irlap_adjust_qos_settings(&self->qos_tx);
00262
00263 IRDA_DEBUG(2, "Setting BAUD_RATE to %d bps.\n",
00264 self->qos_tx.baud_rate.value);
00265 IRDA_DEBUG(2, "Setting DATA_SIZE to %d bytes\n",
00266 self->qos_tx.data_size.value);
00267 IRDA_DEBUG(2, "Setting WINDOW_SIZE to %d\n",
00268 self->qos_tx.window_size.value);
00269 IRDA_DEBUG(2, "Setting XBOFS to %d\n",
00270 self->qos_tx.additional_bofs.value);
00271 IRDA_DEBUG(2, "Setting MAX_TURN_TIME to %d ms.\n",
00272 self->qos_tx.max_turn_time.value);
00273 IRDA_DEBUG(2, "Setting MIN_TURN_TIME to %d usecs.\n",
00274 self->qos_tx.min_turn_time.value);
00275 IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n",
00276 self->qos_tx.link_disc_time.value);
00277 #ifdef CONFIG_IRDA_COMPRESSION
00278 IRDA_DEBUG(2, "Setting COMPRESSION to %d\n",
00279 self->qos_tx.compression.value);
00280 #endif
00281 return ret;
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 int irlap_insert_qos_negotiation_params(struct irlap_cb *self,
00291 struct sk_buff *skb)
00292 {
00293 int ret;
00294
00295
00296 ret = irda_param_insert(self, PI_BAUD_RATE, skb->tail,
00297 skb_tailroom(skb), &irlap_param_info);
00298 if (ret < 0)
00299 return ret;
00300 skb_put(skb, ret);
00301
00302
00303 ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb->tail,
00304 skb_tailroom(skb), &irlap_param_info);
00305 if (ret < 0)
00306 return ret;
00307 skb_put(skb, ret);
00308
00309
00310 ret = irda_param_insert(self, PI_DATA_SIZE, skb->tail,
00311 skb_tailroom(skb), &irlap_param_info);
00312 if (ret < 0)
00313 return ret;
00314 skb_put(skb, ret);
00315
00316
00317 ret = irda_param_insert(self, PI_WINDOW_SIZE, skb->tail,
00318 skb_tailroom(skb), &irlap_param_info);
00319 if (ret < 0)
00320 return ret;
00321 skb_put(skb, ret);
00322
00323
00324 ret = irda_param_insert(self, PI_ADD_BOFS, skb->tail,
00325 skb_tailroom(skb), &irlap_param_info);
00326 if (ret < 0)
00327 return ret;
00328 skb_put(skb, ret);
00329
00330
00331 ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb->tail,
00332 skb_tailroom(skb), &irlap_param_info);
00333 if (ret < 0)
00334 return ret;
00335 skb_put(skb, ret);
00336
00337
00338 ret = irda_param_insert(self, PI_LINK_DISC, skb->tail,
00339 skb_tailroom(skb), &irlap_param_info);
00340 if (ret < 0)
00341 return ret;
00342 skb_put(skb, ret);
00343
00344 return 0;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get)
00354 {
00355 __u16 final;
00356
00357 struct irlap_cb *self = (struct irlap_cb *) instance;
00358
00359 ASSERT(self != NULL, return -1;);
00360 ASSERT(self->magic == LAP_MAGIC, return -1;);
00361
00362 if (get) {
00363 param->pv.i = self->qos_rx.baud_rate.bits;
00364 IRDA_DEBUG(2, __FUNCTION__ "(), baud rate = 0x%02x\n",
00365 param->pv.i);
00366 } else {
00367
00368
00369
00370
00371 IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", param->pv.s);
00372 final = param->pv.s & self->qos_rx.baud_rate.bits;
00373
00374 IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final);
00375 self->qos_tx.baud_rate.bits = final;
00376 self->qos_rx.baud_rate.bits = final;
00377 }
00378 return 0;
00379 }
00380
00381
00382
00383
00384
00385
00386
00387 static int irlap_param_link_disconnect(void *instance, irda_param_t *param,
00388 int get)
00389 {
00390 __u16 final;
00391
00392 struct irlap_cb *self = (struct irlap_cb *) instance;
00393
00394 ASSERT(self != NULL, return -1;);
00395 ASSERT(self->magic == LAP_MAGIC, return -1;);
00396
00397 if (get)
00398 param->pv.b = self->qos_rx.link_disc_time.bits;
00399 else {
00400
00401
00402
00403
00404 IRDA_DEBUG(2, "LINK_DISC: %02x\n", param->pv.b);
00405 final = param->pv.b & self->qos_rx.link_disc_time.bits;
00406
00407 IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final);
00408 self->qos_tx.link_disc_time.bits = final;
00409 self->qos_rx.link_disc_time.bits = final;
00410 }
00411 return 0;
00412 }
00413
00414
00415
00416
00417
00418
00419
00420
00421 static int irlap_param_max_turn_time(void *instance, irda_param_t *param,
00422 int get)
00423 {
00424 struct irlap_cb *self = (struct irlap_cb *) instance;
00425
00426 ASSERT(self != NULL, return -1;);
00427 ASSERT(self->magic == LAP_MAGIC, return -1;);
00428
00429 if (get)
00430 param->pv.b = self->qos_rx.max_turn_time.bits;
00431 else
00432 self->qos_tx.max_turn_time.bits = param->pv.b;
00433
00434 return 0;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444 static int irlap_param_data_size(void *instance, irda_param_t *param, int get)
00445 {
00446 struct irlap_cb *self = (struct irlap_cb *) instance;
00447
00448 ASSERT(self != NULL, return -1;);
00449 ASSERT(self->magic == LAP_MAGIC, return -1;);
00450
00451 if (get)
00452 param->pv.b = self->qos_rx.data_size.bits;
00453 else
00454 self->qos_tx.data_size.bits = param->pv.b;
00455
00456 return 0;
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466 static int irlap_param_window_size(void *instance, irda_param_t *param,
00467 int get)
00468 {
00469 struct irlap_cb *self = (struct irlap_cb *) instance;
00470
00471 ASSERT(self != NULL, return -1;);
00472 ASSERT(self->magic == LAP_MAGIC, return -1;);
00473
00474 if (get)
00475 param->pv.b = self->qos_rx.window_size.bits;
00476 else
00477 self->qos_tx.window_size.bits = param->pv.b;
00478
00479 return 0;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488 static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get)
00489 {
00490 struct irlap_cb *self = (struct irlap_cb *) instance;
00491
00492 ASSERT(self != NULL, return -1;);
00493 ASSERT(self->magic == LAP_MAGIC, return -1;);
00494
00495 if (get)
00496 param->pv.b = self->qos_rx.additional_bofs.bits;
00497 else
00498 self->qos_tx.additional_bofs.bits = param->pv.b;
00499
00500 return 0;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509 static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
00510 int get)
00511 {
00512 struct irlap_cb *self = (struct irlap_cb *) instance;
00513
00514 ASSERT(self != NULL, return -1;);
00515 ASSERT(self->magic == LAP_MAGIC, return -1;);
00516
00517 if (get)
00518 param->pv.b = self->qos_rx.min_turn_time.bits;
00519 else
00520 self->qos_tx.min_turn_time.bits = param->pv.b;
00521
00522 return 0;
00523 }
00524
00525
00526
00527
00528
00529
00530
00531 __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
00532 {
00533 __u32 line_capacity;
00534 int i,j;
00535
00536 IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, max_turn_time=%d\n",
00537 speed, max_turn_time);
00538
00539 i = value_index(speed, baud_rates);
00540 j = value_index(max_turn_time, max_turn_times);
00541
00542 ASSERT(((i >=0) && (i <=10)), return 0;);
00543 ASSERT(((j >=0) && (j <=4)), return 0;);
00544
00545 line_capacity = max_line_capacities[i][j];
00546
00547 IRDA_DEBUG(2, __FUNCTION__ "(), line capacity=%d bytes\n",
00548 line_capacity);
00549
00550 return line_capacity;
00551 }
00552
00553 __u32 irlap_requested_line_capacity(struct qos_info *qos)
00554 { __u32 line_capacity;
00555
00556 line_capacity = qos->window_size.value *
00557 (qos->data_size.value + 6 + qos->additional_bofs.value) +
00558 irlap_min_turn_time_in_bytes(qos->baud_rate.value,
00559 qos->min_turn_time.value);
00560
00561 IRDA_DEBUG(2, __FUNCTION__ "(), requested line capacity=%d\n",
00562 line_capacity);
00563
00564 return line_capacity;
00565 }
00566
00567 __u32 irlap_min_turn_time_in_bytes(__u32 speed, __u32 min_turn_time)
00568 {
00569 __u32 bytes;
00570
00571 bytes = speed * min_turn_time / 10000000;
00572
00573 return bytes;
00574 }
00575
00576 __u32 byte_value(__u8 byte, __u32 *array)
00577 {
00578 int index;
00579
00580 ASSERT(array != NULL, return -1;);
00581
00582 index = msb_index(byte);
00583
00584 return index_value(index, array);
00585 }
00586
00587
00588
00589
00590
00591
00592
00593 int msb_index (__u16 word)
00594 {
00595 __u16 msb = 0x8000;
00596 int index = 15;
00597
00598 while (msb) {
00599 if (word & msb)
00600 break;
00601 msb >>=1;
00602 index--;
00603 }
00604
00605 return index;
00606 }
00607
00608
00609
00610
00611
00612
00613 int value_index(__u32 value, __u32 *array)
00614 {
00615 int i;
00616
00617 for (i=0;i<8;i++)
00618 if (array[i] == value)
00619 break;
00620 return i;
00621 }
00622
00623
00624
00625
00626
00627
00628
00629
00630 __u32 index_value(int index, __u32 *array)
00631 {
00632 return array[index];
00633 }
00634
00635 void irda_qos_bits_to_value(struct qos_info *qos)
00636 {
00637 int index;
00638
00639 ASSERT(qos != NULL, return;);
00640
00641 index = msb_index(qos->baud_rate.bits);
00642 qos->baud_rate.value = baud_rates[index];
00643
00644 index = msb_index(qos->data_size.bits);
00645 qos->data_size.value = data_sizes[index];
00646
00647 index = msb_index(qos->window_size.bits);
00648 qos->window_size.value = index+1;
00649
00650 index = msb_index(qos->min_turn_time.bits);
00651 qos->min_turn_time.value = min_turn_times[index];
00652
00653 index = msb_index(qos->max_turn_time.bits);
00654 qos->max_turn_time.value = max_turn_times[index];
00655
00656 index = msb_index(qos->link_disc_time.bits);
00657 qos->link_disc_time.value = link_disc_times[index];
00658
00659 index = msb_index(qos->additional_bofs.bits);
00660 qos->additional_bofs.value = add_bofs[index];
00661
00662 #ifdef CONFIG_IRDA_COMPRESSION
00663 index = msb_index(qos->compression.bits);
00664 if (index >= 0)
00665 qos->compression.value = compressions[index];
00666 else
00667 qos->compression.value = 0;
00668 #endif
00669 }
00670
00671
00672
00673
00674
00675
00676