Path: blob/master/drivers/isdn/hardware/eicon/diva.c
15115 views
/* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */12#define CARDTYPE_H_WANT_DATA 13#define CARDTYPE_H_WANT_IDI_DATA 04#define CARDTYPE_H_WANT_RESOURCE_DATA 05#define CARDTYPE_H_WANT_FILE_DATA 067#include "platform.h"8#include "debuglib.h"9#include "cardtype.h"10#include "pc.h"11#include "di_defs.h"12#include "di.h"13#include "io.h"14#include "pc_maint.h"15#include "xdi_msg.h"16#include "xdi_adapter.h"17#include "diva_pci.h"18#include "diva.h"1920#ifdef CONFIG_ISDN_DIVAS_PRIPCI21#include "os_pri.h"22#endif23#ifdef CONFIG_ISDN_DIVAS_BRIPCI24#include "os_bri.h"25#include "os_4bri.h"26#endif2728PISDN_ADAPTER IoAdapters[MAX_ADAPTER];29extern IDI_CALL Requests[MAX_ADAPTER];30extern int create_adapter_proc(diva_os_xdi_adapter_t * a);31extern void remove_adapter_proc(diva_os_xdi_adapter_t * a);3233#define DivaIdiReqFunc(N) \34static void DivaIdiRequest##N(ENTITY *e) \35{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }3637/*38** Create own 32 Adapters39*/40DivaIdiReqFunc(0)41DivaIdiReqFunc(1)42DivaIdiReqFunc(2)43DivaIdiReqFunc(3)44DivaIdiReqFunc(4)45DivaIdiReqFunc(5)46DivaIdiReqFunc(6)47DivaIdiReqFunc(7)48DivaIdiReqFunc(8)49DivaIdiReqFunc(9)50DivaIdiReqFunc(10)51DivaIdiReqFunc(11)52DivaIdiReqFunc(12)53DivaIdiReqFunc(13)54DivaIdiReqFunc(14)55DivaIdiReqFunc(15)56DivaIdiReqFunc(16)57DivaIdiReqFunc(17)58DivaIdiReqFunc(18)59DivaIdiReqFunc(19)60DivaIdiReqFunc(20)61DivaIdiReqFunc(21)62DivaIdiReqFunc(22)63DivaIdiReqFunc(23)64DivaIdiReqFunc(24)65DivaIdiReqFunc(25)66DivaIdiReqFunc(26)67DivaIdiReqFunc(27)68DivaIdiReqFunc(28)69DivaIdiReqFunc(29)70DivaIdiReqFunc(30)71DivaIdiReqFunc(31)7273/*74** LOCALS75*/76static LIST_HEAD(adapter_queue);7778typedef struct _diva_get_xlog {79word command;80byte req;81byte rc;82byte data[sizeof(struct mi_pc_maint)];83} diva_get_xlog_t;8485typedef struct _diva_supported_cards_info {86int CardOrdinal;87diva_init_card_proc_t init_card;88} diva_supported_cards_info_t;8990static diva_supported_cards_info_t divas_supported_cards[] = {91#ifdef CONFIG_ISDN_DIVAS_PRIPCI92/*93PRI Cards94*/95{CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},96/*97PRI Rev.2 Cards98*/99{CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},100/*101PRI Rev.2 VoIP Cards102*/103{CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},104#endif105#ifdef CONFIG_ISDN_DIVAS_BRIPCI106/*1074BRI Rev 1 Cards108*/109{CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},110{CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},111/*1124BRI Rev 2 Cards113*/114{CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},115{CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},116/*1174BRI Based BRI Rev 2 Cards118*/119{CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},120{CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},121{CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},122/*123BRI124*/125{CARDTYPE_MAESTRA_PCI, diva_bri_init_card},126#endif127128/*129EOL130*/131{-1}132};133134static void diva_init_request_array(void);135static void *divas_create_pci_card(int handle, void *pci_dev_handle);136137static diva_os_spin_lock_t adapter_lock;138139static int diva_find_free_adapters(int base, int nr)140{141int i;142143for (i = 0; i < nr; i++) {144if (IoAdapters[base + i]) {145return (-1);146}147}148149return (0);150}151152static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what)153{154diva_os_xdi_adapter_t *a = NULL;155156if (what && (what->next != &adapter_queue))157a = list_entry(what->next, diva_os_xdi_adapter_t, link);158159return(a);160}161162/* --------------------------------------------------------------------------163Add card to the card list164-------------------------------------------------------------------------- */165void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)166{167diva_os_spin_lock_magic_t old_irql;168diva_os_xdi_adapter_t *pdiva, *pa;169int i, j, max, nr;170171for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {172if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {173if (!(pdiva = divas_create_pci_card(i, pdev))) {174return NULL;175}176switch (CardOrdinal) {177case CARDTYPE_DIVASRV_Q_8M_PCI:178case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:179case CARDTYPE_DIVASRV_Q_8M_V2_PCI:180case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:181max = MAX_ADAPTER - 4;182nr = 4;183break;184185default:186max = MAX_ADAPTER;187nr = 1;188}189190diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");191192for (i = 0; i < max; i++) {193if (!diva_find_free_adapters(i, nr)) {194pdiva->controller = i + 1;195pdiva->xdi_adapter.ANum = pdiva->controller;196IoAdapters[i] = &pdiva->xdi_adapter;197diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");198create_adapter_proc(pdiva); /* add adapter to proc file system */199200DBG_LOG(("add %s:%d",201CardProperties202[CardOrdinal].Name,203pdiva->controller))204205diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");206pa = pdiva;207for (j = 1; j < nr; j++) { /* slave adapters, if any */208pa = diva_q_get_next(&pa->link);209if (pa && !pa->interface.cleanup_adapter_proc) {210pa->controller = i + 1 + j;211pa->xdi_adapter.ANum = pa->controller;212IoAdapters[i + j] = &pa->xdi_adapter;213diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");214DBG_LOG(("add slave adapter (%d)",215pa->controller))216create_adapter_proc(pa); /* add adapter to proc file system */217diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");218} else {219DBG_ERR(("slave adapter problem"))220break;221}222}223224diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");225return (pdiva);226}227}228229diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");230231/*232Not able to add adapter - remove it and return error233*/234DBG_ERR(("can not alloc request array"))235diva_driver_remove_card(pdiva);236237return NULL;238}239}240241return NULL;242}243244/* --------------------------------------------------------------------------245Called on driver load, MAIN, main, DriverEntry246-------------------------------------------------------------------------- */247int divasa_xdi_driver_entry(void)248{249diva_os_initialize_spin_lock(&adapter_lock, "adapter");250memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));251diva_init_request_array();252253return (0);254}255256/* --------------------------------------------------------------------------257Remove adapter from list258-------------------------------------------------------------------------- */259static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)260{261diva_os_spin_lock_magic_t old_irql;262diva_os_xdi_adapter_t *a = NULL;263264diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");265266if (!list_empty(&adapter_queue)) {267a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);268list_del(adapter_queue.next);269}270271diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");272return (a);273}274275/* --------------------------------------------------------------------------276Remove card from the card list277-------------------------------------------------------------------------- */278void diva_driver_remove_card(void *pdiva)279{280diva_os_spin_lock_magic_t old_irql;281diva_os_xdi_adapter_t *a[4];282diva_os_xdi_adapter_t *pa;283int i;284285pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;286a[1] = a[2] = a[3] = NULL;287288diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");289290for (i = 1; i < 4; i++) {291if ((pa = diva_q_get_next(&pa->link))292&& !pa->interface.cleanup_adapter_proc) {293a[i] = pa;294} else {295break;296}297}298299for (i = 0; ((i < 4) && a[i]); i++) {300list_del(&a[i]->link);301}302303diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");304305(*(a[0]->interface.cleanup_adapter_proc)) (a[0]);306307for (i = 0; i < 4; i++) {308if (a[i]) {309if (a[i]->controller) {310DBG_LOG(("remove adapter (%d)",311a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;312remove_adapter_proc(a[i]);313}314diva_os_free(0, a[i]);315}316}317}318319/* --------------------------------------------------------------------------320Create diva PCI adapter and init internal adapter structures321-------------------------------------------------------------------------- */322static void *divas_create_pci_card(int handle, void *pci_dev_handle)323{324diva_supported_cards_info_t *pI = &divas_supported_cards[handle];325diva_os_spin_lock_magic_t old_irql;326diva_os_xdi_adapter_t *a;327328DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))329330if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {331DBG_ERR(("A: can't alloc adapter"));332return NULL;333}334335memset(a, 0x00, sizeof(*a));336337a->CardIndex = handle;338a->CardOrdinal = pI->CardOrdinal;339a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;340a->xdi_adapter.cardType = a->CardOrdinal;341a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);342a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);343a->resources.pci.hdev = pci_dev_handle;344345/*346Add master adapter first, so slave adapters will receive higher347numbers as master adapter348*/349diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");350list_add_tail(&a->link, &adapter_queue);351diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");352353if ((*(pI->init_card)) (a)) {354diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");355list_del(&a->link);356diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");357diva_os_free(0, a);358DBG_ERR(("A: can't get adapter resources"));359return NULL;360}361362return (a);363}364365/* --------------------------------------------------------------------------366Called on driver unload FINIT, finit, Unload367-------------------------------------------------------------------------- */368void divasa_xdi_driver_unload(void)369{370diva_os_xdi_adapter_t *a;371372while ((a = get_and_remove_from_queue())) {373if (a->interface.cleanup_adapter_proc) {374(*(a->interface.cleanup_adapter_proc)) (a);375}376if (a->controller) {377IoAdapters[a->controller - 1] = NULL;378remove_adapter_proc(a);379}380diva_os_free(0, a);381}382diva_os_destroy_spin_lock(&adapter_lock, "adapter");383}384385/*386** Receive and process command from user mode utility387*/388void *diva_xdi_open_adapter(void *os_handle, const void __user *src,389int length,390divas_xdi_copy_from_user_fn_t cp_fn)391{392diva_xdi_um_cfg_cmd_t msg;393diva_os_xdi_adapter_t *a = NULL;394diva_os_spin_lock_magic_t old_irql;395struct list_head *tmp;396397if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {398DBG_ERR(("A: A(?) open, msg too small (%d < %d)",399length, sizeof(diva_xdi_um_cfg_cmd_t)))400return NULL;401}402if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {403DBG_ERR(("A: A(?) open, write error"))404return NULL;405}406diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");407list_for_each(tmp, &adapter_queue) {408a = list_entry(tmp, diva_os_xdi_adapter_t, link);409if (a->controller == (int)msg.adapter)410break;411a = NULL;412}413diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");414415if (!a) {416DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))417}418419return (a);420}421422/*423** Easy cleanup mailbox status424*/425void diva_xdi_close_adapter(void *adapter, void *os_handle)426{427diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;428429a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;430if (a->xdi_mbox.data) {431diva_os_free(0, a->xdi_mbox.data);432a->xdi_mbox.data = NULL;433}434}435436int437diva_xdi_write(void *adapter, void *os_handle, const void __user *src,438int length, divas_xdi_copy_from_user_fn_t cp_fn)439{440diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;441void *data;442443if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {444DBG_ERR(("A: A(%d) write, mbox busy", a->controller))445return (-1);446}447448if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {449DBG_ERR(("A: A(%d) write, message too small (%d < %d)",450a->controller, length,451sizeof(diva_xdi_um_cfg_cmd_t)))452return (-3);453}454455if (!(data = diva_os_malloc(0, length))) {456DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))457return (-2);458}459460length = (*cp_fn) (os_handle, data, src, length);461if (length > 0) {462if ((*(a->interface.cmd_proc))463(a, (diva_xdi_um_cfg_cmd_t *) data, length)) {464length = -3;465}466} else {467DBG_ERR(("A: A(%d) write error (%d)", a->controller,468length))469}470471diva_os_free(0, data);472473return (length);474}475476/*477** Write answers to user mode utility, if any478*/479int480diva_xdi_read(void *adapter, void *os_handle, void __user *dst,481int max_length, divas_xdi_copy_to_user_fn_t cp_fn)482{483diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;484int ret;485486if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {487DBG_ERR(("A: A(%d) rx mbox empty", a->controller))488return (-1);489}490if (!a->xdi_mbox.data) {491a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;492DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))493return (-2);494}495496if (max_length < a->xdi_mbox.data_length) {497DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",498a->controller, max_length,499a->xdi_mbox.data_length))500return (-3);501}502503ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,504a->xdi_mbox.data_length);505if (ret > 0) {506diva_os_free(0, a->xdi_mbox.data);507a->xdi_mbox.data = NULL;508a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;509}510511return (ret);512}513514515irqreturn_t diva_os_irq_wrapper(int irq, void *context)516{517diva_os_xdi_adapter_t *a = context;518diva_xdi_clear_interrupts_proc_t clear_int_proc;519520if (!a || !a->xdi_adapter.diva_isr_handler)521return IRQ_NONE;522523if ((clear_int_proc = a->clear_interrupts_proc)) {524(*clear_int_proc) (a);525a->clear_interrupts_proc = NULL;526return IRQ_HANDLED;527}528529(*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);530return IRQ_HANDLED;531}532533static void diva_init_request_array(void)534{535Requests[0] = DivaIdiRequest0;536Requests[1] = DivaIdiRequest1;537Requests[2] = DivaIdiRequest2;538Requests[3] = DivaIdiRequest3;539Requests[4] = DivaIdiRequest4;540Requests[5] = DivaIdiRequest5;541Requests[6] = DivaIdiRequest6;542Requests[7] = DivaIdiRequest7;543Requests[8] = DivaIdiRequest8;544Requests[9] = DivaIdiRequest9;545Requests[10] = DivaIdiRequest10;546Requests[11] = DivaIdiRequest11;547Requests[12] = DivaIdiRequest12;548Requests[13] = DivaIdiRequest13;549Requests[14] = DivaIdiRequest14;550Requests[15] = DivaIdiRequest15;551Requests[16] = DivaIdiRequest16;552Requests[17] = DivaIdiRequest17;553Requests[18] = DivaIdiRequest18;554Requests[19] = DivaIdiRequest19;555Requests[20] = DivaIdiRequest20;556Requests[21] = DivaIdiRequest21;557Requests[22] = DivaIdiRequest22;558Requests[23] = DivaIdiRequest23;559Requests[24] = DivaIdiRequest24;560Requests[25] = DivaIdiRequest25;561Requests[26] = DivaIdiRequest26;562Requests[27] = DivaIdiRequest27;563Requests[28] = DivaIdiRequest28;564Requests[29] = DivaIdiRequest29;565Requests[30] = DivaIdiRequest30;566Requests[31] = DivaIdiRequest31;567}568569void diva_xdi_display_adapter_features(int card)570{571dword features;572if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {573return;574}575card--;576features = IoAdapters[card]->Properties.Features;577578DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))579DBG_LOG((" DI_FAX3 : %s",580(features & DI_FAX3) ? "Y" : "N"))581DBG_LOG((" DI_MODEM : %s",582(features & DI_MODEM) ? "Y" : "N"))583DBG_LOG((" DI_POST : %s",584(features & DI_POST) ? "Y" : "N"))585DBG_LOG((" DI_V110 : %s",586(features & DI_V110) ? "Y" : "N"))587DBG_LOG((" DI_V120 : %s",588(features & DI_V120) ? "Y" : "N"))589DBG_LOG((" DI_POTS : %s",590(features & DI_POTS) ? "Y" : "N"))591DBG_LOG((" DI_CODEC : %s",592(features & DI_CODEC) ? "Y" : "N"))593DBG_LOG((" DI_MANAGE : %s",594(features & DI_MANAGE) ? "Y" : "N"))595DBG_LOG((" DI_V_42 : %s",596(features & DI_V_42) ? "Y" : "N"))597DBG_LOG((" DI_EXTD_FAX : %s",598(features & DI_EXTD_FAX) ? "Y" : "N"))599DBG_LOG((" DI_AT_PARSER : %s",600(features & DI_AT_PARSER) ? "Y" : "N"))601DBG_LOG((" DI_VOICE_OVER_IP : %s",602(features & DI_VOICE_OVER_IP) ? "Y" : "N"))603}604605void diva_add_slave_adapter(diva_os_xdi_adapter_t * a)606{607diva_os_spin_lock_magic_t old_irql;608609diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");610list_add_tail(&a->link, &adapter_queue);611diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");612}613614int diva_card_read_xlog(diva_os_xdi_adapter_t * a)615{616diva_get_xlog_t *req;617byte *data;618619if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {620return (-1);621}622if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {623return (-1);624}625memset(data, 0x00, sizeof(struct mi_pc_maint));626627if (!(req = diva_os_malloc(0, sizeof(*req)))) {628diva_os_free(0, data);629return (-1);630}631req->command = 0x0400;632req->req = LOG;633req->rc = 0x00;634635(*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);636637if (!req->rc || req->req) {638diva_os_free(0, data);639diva_os_free(0, req);640return (-1);641}642643memcpy(data, &req->req, sizeof(struct mi_pc_maint));644645diva_os_free(0, req);646647a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);648a->xdi_mbox.data = data;649a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;650651return (0);652}653654void xdiFreeFile(void *handle)655{656}657658659