/* * com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * authors: * (C) 2008 Andreas Schuler * (C) 2008 Matthias Wenzel * */ #include "dect.h" #define DECT_A_TA 0xe0 #define DECT_A_Q1 0x10 #define DECT_A_BA 0x0e #define DECT_A_Q2 0x01 #define DECT_Q_TYPE 0x80 #define DECT_N_TYPE 0x60 #define DECT_P_TYPE 0xe0 #define DECT_Q_HEAD 0xf0 #define DECT_Q_HEAD_SSINFO 0x00 /* Static System info */ #define DECT_Q_HEAD_EXTRF1 0x20 /* Extended RF Carriers Part 1 */ #define DECT_Q_HEAD_FPC 0x30 /* Fixed Part Capabilities */ #define DECT_Q_HEAD_MULTIFN 0x60 /* Multi Frame Number */ #define DECT_Q_SSINFO_SLOT 0x0f #define DECT_P_EXTFLAG 0x80 #define DECT_P_HEAD 0x70 #define DECT_P_HEAD_ZEROLP 0x00 /* Zero Length Page */ #define DECT_P_HEAD_SHORTLP 0x10 /* Short Length Page */ #define DECT_P_HEAD_FULLLP 0x20 /* Full Length Page */ #define DECT_P_HEAD_MACRES 0x30 /* MAC Resume Page */ #define DECT_P_HEAD_NOTLAST36 0x40 /* Not the Last 36 Bits of Long Page */ #define DECT_P_HEAD_FIRST36 0x50 /* First 36 Bit of Long Page */ #define DECT_P_HEAD_LAST26 0x60 /* Last 36 Bit of Long Page */ #define DECT_P_HEAD_ALLOFLP 0x70 /* All of Long Page (first and last) */ #define DECT_P_INFOTYPE 0xf0 #define DECT_P_IT_FILLBITS 0x00 /* Fill Bits */ #define DECT_P_IT_BFCIRCUIT 0x10 /* Blind Full Slot Information for \ Circuit Mode Service */ #define DECT_P_IT_OTHERBEAR 0x20 /* Other Bearer */ #define DECT_P_IT_RECOTHERBEAR 0x30 /* Recommended Other Bearer */ #define DECT_P_IT_GOODRFPBEAR 0x40 /* Good RFP Bearer */ #define DECT_P_IT_DUMMYCLPOS 0x50 /* Dummy or C/L Bearer Position */ #define DECT_P_IT_EXTMODULTYPE 0x60 /* Extended Modulation Type */ #define DECT_P_IT_ESCAPE 0x70 /* Escape */ #define DECT_P_IT_DUMMYCLBEARM 0x80 /* Dummy or C/L Bearer Marker */ #define DECT_P_IT_REPLACEINFO 0x90 /* Bearer Handover/Replacement \ Information */ #define DECT_P_IT_BEARERPOS_SN 0x0f /* Slot Number */ #define DECT_P_IT_BEARERPOS_SP 0xc0 /* Start Position */ #define DECT_P_IT_BEARERPOS_CN 0x3f /* Channel */ int dect_is_RFPI_Packet(unsigned char *packet) { if ((packet[5] & DECT_A_TA) == DECT_N_TYPE) return 1; return 0; } int dect_compare_RFPI(unsigned char *packet, unsigned char* RFPI) { if ((packet[5] & DECT_A_TA) == DECT_N_TYPE) { if (!memcmp(&packet[6], RFPI, 5)) return 1; } return 0; } int dect_has_b_field(unsigned char *packet) { if ((packet[5] & DECT_A_BA) != DECT_A_BA) return 1; return 0; } int dect_get_slot(unsigned char *packet) { int slot = -1; if ((packet[5] & DECT_A_TA) == DECT_Q_TYPE) { if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_SSINFO) { slot = packet[6] & DECT_Q_SSINFO_SLOT; } } return slot; } int dect_is_multiframe_number(unsigned char *packet) { if ((packet[5] & DECT_A_TA) == DECT_Q_TYPE) { /*printk("bl"); */ if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_MULTIFN) { /*printk("aa\n"); */ return 1; } } return 0; } int dect_is_fp_packet(unsigned char *packet) { if ( (packet[3] == 0xe9) && (packet[4] == 0x8a) ) return 1; return 0; } int dect_is_pp_packet(unsigned char *packet) { if ( (packet[3] == 0x16) && (packet[4] == 0x75) ) return 1; return 0; } int dect_update_slottable(struct dect_slot_info *slottable, int slot, unsigned char *packet) { if (slottable[slot].type == DECT_SLOTTYPE_SCAN) { //printk("received packet on scanslot %u on carrier %u\n", slot, slottable[slot].channel); slottable[slot].type = DECT_SLOTTYPE_CARRIER; if (slottable[slot].channel == 0) slottable[slot].channel = 9; else slottable[slot].channel--; slottable[slot].errcnt = 0; slottable[slot].update = 1; if (slot > 12) { slottable[slot-12].type = DECT_SLOTTYPE_CARRIER; if (slottable[slot-12].channel == 0) slottable[slot-12].channel = 9; else slottable[slot-12].channel--; slottable[slot-12].errcnt = 0; slottable[slot].update = 1; } else { slottable[slot+12].type = DECT_SLOTTYPE_CARRIER; if (slottable[slot+12].channel == 0) slottable[slot+12].channel = 9; else slottable[slot+12].channel--; slottable[slot+12].errcnt = 0; slottable[slot].update = 1; } } if (dect_is_fp_packet(packet)) { switch(packet[5] & DECT_A_TA) { case DECT_P_TYPE: if ( ( (packet[6] & DECT_P_HEAD) == DECT_P_HEAD_ZEROLP) || ( (packet[6] & DECT_P_HEAD) == DECT_P_HEAD_SHORTLP) ) { switch((packet[9] & DECT_P_INFOTYPE)) { case DECT_P_IT_OTHERBEAR: { int newslot = (packet[9] & DECT_P_IT_BEARERPOS_SN) % 12; slottable[newslot].active = 1; slottable[newslot].channel = packet[10] & DECT_P_IT_BEARERPOS_CN; slottable[newslot].type = DECT_SLOTTYPE_CARRIER; slottable[newslot].errcnt = 0; slottable[newslot].update = 1; slottable[newslot+12].active = 1; slottable[newslot+12].channel = packet[10] & DECT_P_IT_BEARERPOS_CN; slottable[newslot+12].type = DECT_SLOTTYPE_CARRIER; slottable[newslot+12].errcnt = 0; slottable[newslot+12].update = 1; //printk("\n\nstation switching to slot %u channel %u\n\n",newslot, packet[10] & DECT_P_IT_BEARERPOS_CN); return 1; } case DECT_P_IT_BFCIRCUIT: /* set scanning slots */ { int i, x, ret = 0; unsigned int slots = (((unsigned int)(packet[9] & ~DECT_P_INFOTYPE)) << 8) | packet[10]; for (i=0; i<12; i++) { x = (slots & 0x800 ? 1:0); slots <<= 1; if (x && (!slottable[i].active)) { //printk("scanning on slot %u\n", i); slottable[i].active = 1; slottable[i].channel = 0; /* channel unknown at this position */ slottable[i].type = DECT_SLOTTYPE_SCAN; slottable[i].errcnt = 0; slottable[i].update = 1; ret = 1; } if (x && (!slottable[i+12].active)) { //printk("scanning on slot %u\n", i + 12); slottable[i+12].active = 1; slottable[i+12].channel = 0; /* channel unknown at this position */ slottable[i+12].type = DECT_SLOTTYPE_SCAN; slottable[i+12].errcnt = 0; slottable[i+12].update = 1; ret = 1; } } return ret; } } } break; case DECT_Q_TYPE: if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_SSINFO) { uint8_t pscan = packet[10]; int i, ret = 0; for (i=0; i<24; i++) { if (slottable[i].active) { if (slottable[i].type == DECT_SLOTTYPE_SCAN) { /* if (pscan == 0) pscan = 9; else pscan--; */ slottable[i].channel = pscan; slottable[i].update = 1; ret = 1; } } } return ret; } break; } } return 0; } int dect_receive_error(struct dect_slot_info *slottable, int slot) { //printk("slot:%u,errcnt:%u,type:%u,channel:%u\n",slot,slottable[slot].errcnt,slottable[slot].type,slottable[slot].channel); slottable[slot].errcnt++; if (slottable[slot].type != DECT_SLOTTYPE_SCAN) { if (slottable[slot].errcnt > 32) { slottable[slot].active = 0; slottable[slot].update = 1; //printk("slot %u on channel %u died\n", slot, slottable[slot].channel); return 1; } } return 0; } int dect_update_scanchannels(struct dect_slot_info *slottable) { int i, ret = 0; for (i=0; i<24; i++) /* Increment primary scan channel */ { if (slottable[i].active) { if (slottable[i].type == DECT_SLOTTYPE_SCAN) { slottable[i].channel++; if (slottable[i].channel > 9) slottable[i].channel = 0; slottable[i].update = 1; ret = 1; //printk("slot %u will now scan on carrier %u\n", i, slottable[i].channel); } } } return ret; }