me8254_subdevice_t* me8254_constr(uint16_t device_id, void* reg_base, unsigned int me8254_idx, unsigned int ctr_idx, me_lock_t* ctrl_reg_lock, me_lock_t* clk_src_reg_lock) { me8254_subdevice_t *subdevice; PDEBUG("executed.\n"); /** @todo Checkings should be removed. We can safetly assume that data passed from upper level are correct. */ // Check if counter index is out of range if (ctr_idx > 2) { PERROR("Counter index is out of range.\n"); return NULL; } // Check device specific values. switch (device_id) { case PCI_DEVICE_ID_MEILHAUS_ME140A: case PCI_DEVICE_ID_MEILHAUS_ME14EA: case PCI_DEVICE_ID_MEILHAUS_ME4610: case PCI_DEVICE_ID_MEILHAUS_ME4660: case PCI_DEVICE_ID_MEILHAUS_ME4660I: case PCI_DEVICE_ID_MEILHAUS_ME4660S: case PCI_DEVICE_ID_MEILHAUS_ME4660IS: case PCI_DEVICE_ID_MEILHAUS_ME4670: case PCI_DEVICE_ID_MEILHAUS_ME4670I: case PCI_DEVICE_ID_MEILHAUS_ME4670S: case PCI_DEVICE_ID_MEILHAUS_ME4670IS: case PCI_DEVICE_ID_MEILHAUS_ME4680: case PCI_DEVICE_ID_MEILHAUS_ME4680I: case PCI_DEVICE_ID_MEILHAUS_ME4680S: case PCI_DEVICE_ID_MEILHAUS_ME4680IS: case PCI_DEVICE_ID_MEILHAUS_ME4560: case PCI_DEVICE_ID_MEILHAUS_ME4560I: case PCI_DEVICE_ID_MEILHAUS_ME4560S: case PCI_DEVICE_ID_MEILHAUS_ME4560IS: case PCI_DEVICE_ID_MEILHAUS_ME4570: case PCI_DEVICE_ID_MEILHAUS_ME4570I: case PCI_DEVICE_ID_MEILHAUS_ME4570S: case PCI_DEVICE_ID_MEILHAUS_ME4570IS: case PCI_DEVICE_ID_MEILHAUS_ME4760: case PCI_DEVICE_ID_MEILHAUS_ME4760I: case PCI_DEVICE_ID_MEILHAUS_ME4760S: case PCI_DEVICE_ID_MEILHAUS_ME4760IS: case PCI_DEVICE_ID_MEILHAUS_ME4770: case PCI_DEVICE_ID_MEILHAUS_ME4770I: case PCI_DEVICE_ID_MEILHAUS_ME4770S: case PCI_DEVICE_ID_MEILHAUS_ME4770IS: case PCI_DEVICE_ID_MEILHAUS_ME4780: case PCI_DEVICE_ID_MEILHAUS_ME4780I: case PCI_DEVICE_ID_MEILHAUS_ME4780S: case PCI_DEVICE_ID_MEILHAUS_ME4780IS: case PCI_DEVICE_ID_MEILHAUS_ME4860: case PCI_DEVICE_ID_MEILHAUS_ME4860I: case PCI_DEVICE_ID_MEILHAUS_ME4860S: case PCI_DEVICE_ID_MEILHAUS_ME4860IS: case PCI_DEVICE_ID_MEILHAUS_ME4870: case PCI_DEVICE_ID_MEILHAUS_ME4870I: case PCI_DEVICE_ID_MEILHAUS_ME4870S: case PCI_DEVICE_ID_MEILHAUS_ME4870IS: case PCI_DEVICE_ID_MEILHAUS_ME4880: case PCI_DEVICE_ID_MEILHAUS_ME4880I: case PCI_DEVICE_ID_MEILHAUS_ME4880S: case PCI_DEVICE_ID_MEILHAUS_ME4880IS: case PCI_DEVICE_ID_MEILHAUS_ME0752: case PCI_DEVICE_ID_MEILHAUS_ME0754: case PCI_DEVICE_ID_MEILHAUS_ME0762: case PCI_DEVICE_ID_MEILHAUS_ME0764: case PCI_DEVICE_ID_MEILHAUS_ME0772: case PCI_DEVICE_ID_MEILHAUS_ME0774: case PCI_DEVICE_ID_MEILHAUS_ME0782: case PCI_DEVICE_ID_MEILHAUS_ME0784: case PCI_DEVICE_ID_MEILHAUS_ME8100_A: case PCI_DEVICE_ID_MEILHAUS_ME8100_B: if (me8254_idx > 0) { PERROR("8254 index is out of range. Must be 0.\n"); return NULL; } break; case PCI_DEVICE_ID_MEILHAUS_ME140B: case PCI_DEVICE_ID_MEILHAUS_ME14EB: if (me8254_idx > 1) { PERROR("8254 index is out of range. Must be 0 or 1.\n"); return NULL; } break; case PCI_DEVICE_ID_MEILHAUS_ME140C: if (me8254_idx > 4) { PERROR("8254 index is out of range. Must be between 0 and 3.\n"); return NULL; } case PCI_DEVICE_ID_MEILHAUS_ME140D: if (me8254_idx > 9) { PERROR("8254 index is out of range. Must be between 0 and 8.\n"); return NULL; } break; default: PERROR_CRITICAL("8254 registred for %x!\n", device_id); return NULL; } // Allocate memory for subdevice instance subdevice = kzalloc(sizeof(me8254_subdevice_t), GFP_KERNEL); if (!subdevice) { PERROR("Cannot get memory for 8254 instance.\n"); return NULL; } // Initialize subdevice base class if (me_subdevice_init(&subdevice->base)) { PERROR("Cannot initialize subdevice base class instance.\n"); kfree(subdevice); return NULL; } // Initialize spin locks. subdevice->ctrl_reg_lock = ctrl_reg_lock; subdevice->clk_src_reg_lock = clk_src_reg_lock; // Save type of Meilhaus device subdevice->device_id = device_id; // Save the subdevice indexes. subdevice->me8254_idx = me8254_idx; subdevice->ctr_idx = ctr_idx; subdevice->base.idx = ctr_idx + (me8254_idx * 3); /** @todo Setting flags for particular implementations create portibility problem. Flags should be passed from upper level. Also registers should be some how provided by upper level call. */ // Do device specific initialization switch (device_id) { case PCI_DEVICE_ID_MEILHAUS_ME140A: case PCI_DEVICE_ID_MEILHAUS_ME14EA: case PCI_DEVICE_ID_MEILHAUS_ME140B: case PCI_DEVICE_ID_MEILHAUS_ME14EB: // Initialize the counters capabilities subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; if (ctr_idx == 0) subdevice->caps |= ME_CAPS_CTR_CLK_INTERNAL_1MHZ | ME_CAPS_CTR_CLK_INTERNAL_10MHZ; else subdevice->caps |= ME_CAPS_CTR_CLK_PREVIOUS; // Get the counters registers subdevice->val_reg = me1400AB_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me1400AB_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = me1400AB_get_clk_src_reg(reg_base, me8254_idx, ctr_idx); break; case PCI_DEVICE_ID_MEILHAUS_ME140C: case PCI_DEVICE_ID_MEILHAUS_ME140D: // Initialize the counters capabilities subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL | ME_CAPS_CTR_CLK_PREVIOUS; if (ctr_idx == 0) { subdevice->caps |= ME_CAPS_CTR_CLK_INTERNAL_1MHZ | ME_CAPS_CTR_CLK_INTERNAL_10MHZ; if ((me8254_idx == 0) || (me8254_idx == 5)) {// No cascading for first counter on first chips. subdevice->caps &= ~ME_CAPS_CTR_CLK_PREVIOUS; } } // Get the counters registers subdevice->val_reg = me1400CD_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me1400CD_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = me1400CD_get_clk_src_reg(reg_base, me8254_idx, ctr_idx); break; case PCI_DEVICE_ID_MEILHAUS_ME4610: case PCI_DEVICE_ID_MEILHAUS_ME4660: case PCI_DEVICE_ID_MEILHAUS_ME4660I: case PCI_DEVICE_ID_MEILHAUS_ME4660S: case PCI_DEVICE_ID_MEILHAUS_ME4660IS: case PCI_DEVICE_ID_MEILHAUS_ME4670: case PCI_DEVICE_ID_MEILHAUS_ME4670I: case PCI_DEVICE_ID_MEILHAUS_ME4670S: case PCI_DEVICE_ID_MEILHAUS_ME4670IS: case PCI_DEVICE_ID_MEILHAUS_ME4680: case PCI_DEVICE_ID_MEILHAUS_ME4680I: case PCI_DEVICE_ID_MEILHAUS_ME4680S: case PCI_DEVICE_ID_MEILHAUS_ME4680IS: case PCI_DEVICE_ID_MEILHAUS_ME4560: case PCI_DEVICE_ID_MEILHAUS_ME4560I: case PCI_DEVICE_ID_MEILHAUS_ME4560S: case PCI_DEVICE_ID_MEILHAUS_ME4560IS: case PCI_DEVICE_ID_MEILHAUS_ME4570: case PCI_DEVICE_ID_MEILHAUS_ME4570I: case PCI_DEVICE_ID_MEILHAUS_ME4570S: case PCI_DEVICE_ID_MEILHAUS_ME4570IS: case PCI_DEVICE_ID_MEILHAUS_ME4760: case PCI_DEVICE_ID_MEILHAUS_ME4760I: case PCI_DEVICE_ID_MEILHAUS_ME4760S: case PCI_DEVICE_ID_MEILHAUS_ME4760IS: case PCI_DEVICE_ID_MEILHAUS_ME4770: case PCI_DEVICE_ID_MEILHAUS_ME4770I: case PCI_DEVICE_ID_MEILHAUS_ME4770S: case PCI_DEVICE_ID_MEILHAUS_ME4770IS: case PCI_DEVICE_ID_MEILHAUS_ME4780: case PCI_DEVICE_ID_MEILHAUS_ME4780I: case PCI_DEVICE_ID_MEILHAUS_ME4780S: case PCI_DEVICE_ID_MEILHAUS_ME4780IS: case PCI_DEVICE_ID_MEILHAUS_ME4860: case PCI_DEVICE_ID_MEILHAUS_ME4860I: case PCI_DEVICE_ID_MEILHAUS_ME4860S: case PCI_DEVICE_ID_MEILHAUS_ME4860IS: case PCI_DEVICE_ID_MEILHAUS_ME4870: case PCI_DEVICE_ID_MEILHAUS_ME4870I: case PCI_DEVICE_ID_MEILHAUS_ME4870S: case PCI_DEVICE_ID_MEILHAUS_ME4870IS: case PCI_DEVICE_ID_MEILHAUS_ME4880: case PCI_DEVICE_ID_MEILHAUS_ME4880I: case PCI_DEVICE_ID_MEILHAUS_ME4880S: case PCI_DEVICE_ID_MEILHAUS_ME4880IS: case PCI_DEVICE_ID_MEILHAUS_ME0752: case PCI_DEVICE_ID_MEILHAUS_ME0754: case PCI_DEVICE_ID_MEILHAUS_ME0762: case PCI_DEVICE_ID_MEILHAUS_ME0764: case PCI_DEVICE_ID_MEILHAUS_ME0772: case PCI_DEVICE_ID_MEILHAUS_ME0774: case PCI_DEVICE_ID_MEILHAUS_ME0782: case PCI_DEVICE_ID_MEILHAUS_ME0784: // Initialize the counters capabilities subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; // Get the counters registers subdevice->val_reg = me4600_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me4600_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = 0; // Not used break; case PCI_DEVICE_ID_MEILHAUS_ME8100_A: case PCI_DEVICE_ID_MEILHAUS_ME8100_B: // Initialize the counters capabilities subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; // Get the counters registers subdevice->val_reg = me8100_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me8100_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = 0; // Not used break; default: PERROR("Unknown device type.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } // Overload subdevice base class methods. subdevice->base.me_subdevice_io_reset_subdevice = me8254_io_reset_subdevice; subdevice->base.me_subdevice_io_single_config = me8254_io_single_config; subdevice->base.me_subdevice_io_single_read = me8254_io_single_read; subdevice->base.me_subdevice_io_single_write = me8254_io_single_write; subdevice->base.me_subdevice_query_number_channels = me8254_query_number_channels; subdevice->base.me_subdevice_query_subdevice_type = me8254_query_subdevice_type; subdevice->base.me_subdevice_query_subdevice_caps = me8254_query_subdevice_caps; subdevice->base.me_subdevice_query_subdevice_caps_args = me8254_query_subdevice_caps_args; return subdevice; }
me8254_subdevice_t *me8254_constructor(uint32_t device_id, uint32_t reg_base, unsigned int me8254_idx, unsigned int ctr_idx, spinlock_t * ctrl_reg_lock, spinlock_t * clk_src_reg_lock) { me8254_subdevice_t *subdevice; int err; PDEBUG("executed.\n"); // Allocate memory for subdevice instance subdevice = kmalloc(sizeof(me8254_subdevice_t), GFP_KERNEL); if (!subdevice) { PERROR("Cannot get memory for 8254 instance.\n"); return NULL; } memset(subdevice, 0, sizeof(me8254_subdevice_t)); // Check if counter index is out of range if (ctr_idx > 2) { PERROR("Counter index is out of range.\n"); kfree(subdevice); return NULL; } // Initialize subdevice base class err = me_subdevice_init(&subdevice->base); if (err) { PERROR("Cannot initialize subdevice base class instance.\n"); kfree(subdevice); return NULL; } // Initialize spin locks. spin_lock_init(&subdevice->subdevice_lock); subdevice->ctrl_reg_lock = ctrl_reg_lock; subdevice->clk_src_reg_lock = clk_src_reg_lock; // Save type of Meilhaus device subdevice->device_id = device_id; // Save the indices subdevice->me8254_idx = me8254_idx; subdevice->ctr_idx = ctr_idx; // Do device specific initialization switch (device_id) { case PCI_DEVICE_ID_MEILHAUS_ME140A: case PCI_DEVICE_ID_MEILHAUS_ME14EA: // Check if 8254 index is out of range if (me8254_idx > 0) { PERROR("8254 index is out of range.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } case PCI_DEVICE_ID_MEILHAUS_ME140B: // Fall through case PCI_DEVICE_ID_MEILHAUS_ME14EB: // Check if 8254 index is out of range if (me8254_idx > 1) { PERROR("8254 index is out of range.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } // Initialize the counters capabilities if (ctr_idx == 0) subdevice->caps = ME_CAPS_CTR_CLK_INTERNAL_1MHZ | ME_CAPS_CTR_CLK_INTERNAL_10MHZ | ME_CAPS_CTR_CLK_EXTERNAL; else subdevice->caps = ME_CAPS_CTR_CLK_PREVIOUS | ME_CAPS_CTR_CLK_EXTERNAL; // Get the counters registers subdevice->val_reg = me1400AB_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me1400AB_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = me1400AB_get_clk_src_reg(reg_base, me8254_idx, ctr_idx); break; case PCI_DEVICE_ID_MEILHAUS_ME140C: // Check if 8254 index is out of range if (me8254_idx > 4) { PERROR("8254 index is out of range.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } case PCI_DEVICE_ID_MEILHAUS_ME140D: // Check if 8254 index is out of range if (me8254_idx > 9) { PERROR("8254 index is out of range.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } // Initialize the counters capabilities if (ctr_idx == 0) { if (me8254_idx == 0) subdevice->caps = ME_CAPS_CTR_CLK_PREVIOUS | ME_CAPS_CTR_CLK_INTERNAL_1MHZ | ME_CAPS_CTR_CLK_INTERNAL_10MHZ | ME_CAPS_CTR_CLK_EXTERNAL; else subdevice->caps = ME_CAPS_CTR_CLK_INTERNAL_1MHZ | ME_CAPS_CTR_CLK_INTERNAL_10MHZ | ME_CAPS_CTR_CLK_EXTERNAL; } else subdevice->caps = ME_CAPS_CTR_CLK_PREVIOUS | ME_CAPS_CTR_CLK_EXTERNAL; // Get the counters registers subdevice->val_reg = me1400CD_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me1400CD_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = me1400CD_get_clk_src_reg(reg_base, me8254_idx, ctr_idx); break; case PCI_DEVICE_ID_MEILHAUS_ME4610: case PCI_DEVICE_ID_MEILHAUS_ME4660: case PCI_DEVICE_ID_MEILHAUS_ME4660I: case PCI_DEVICE_ID_MEILHAUS_ME4660S: case PCI_DEVICE_ID_MEILHAUS_ME4660IS: case PCI_DEVICE_ID_MEILHAUS_ME4670: case PCI_DEVICE_ID_MEILHAUS_ME4670I: case PCI_DEVICE_ID_MEILHAUS_ME4670S: case PCI_DEVICE_ID_MEILHAUS_ME4670IS: case PCI_DEVICE_ID_MEILHAUS_ME4680: case PCI_DEVICE_ID_MEILHAUS_ME4680I: case PCI_DEVICE_ID_MEILHAUS_ME4680S: case PCI_DEVICE_ID_MEILHAUS_ME4680IS: // Check if 8254 index is out of range if (me8254_idx > 0) { PERROR("8254 index is out of range.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } // Initialize the counters capabilities subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; // Get the counters registers subdevice->val_reg = me4600_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me4600_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = 0; // Not used break; case PCI_DEVICE_ID_MEILHAUS_ME8100_A: case PCI_DEVICE_ID_MEILHAUS_ME8100_B: // Check if 8254 index is out of range if (me8254_idx > 0) { PERROR("8254 index is out of range.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } // Initialize the counters capabilities subdevice->caps = ME_CAPS_CTR_CLK_EXTERNAL; // Get the counters registers subdevice->val_reg = me8100_get_val_reg(reg_base, me8254_idx, ctr_idx); subdevice->ctrl_reg = me8100_get_ctrl_reg(reg_base, me8254_idx, ctr_idx); subdevice->clk_src_reg = 0; // Not used break; case PCI_DEVICE_ID_MEILHAUS_ME4650: case PCI_DEVICE_ID_MEILHAUS_ME1400: case PCI_DEVICE_ID_MEILHAUS_ME14E0: PERROR("No 8254 subdevices available for subdevice device.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; default: PERROR("Unknown device type.\n"); me_subdevice_deinit(&subdevice->base); kfree(subdevice); return NULL; } // Overload subdevice base class methods. subdevice->base.me_subdevice_io_reset_subdevice = me8254_io_reset_subdevice; subdevice->base.me_subdevice_io_single_config = me8254_io_single_config; subdevice->base.me_subdevice_io_single_read = me8254_io_single_read; subdevice->base.me_subdevice_io_single_write = me8254_io_single_write; subdevice->base.me_subdevice_query_number_channels = me8254_query_number_channels; subdevice->base.me_subdevice_query_subdevice_type = me8254_query_subdevice_type; subdevice->base.me_subdevice_query_subdevice_caps = me8254_query_subdevice_caps; subdevice->base.me_subdevice_query_subdevice_caps_args = me8254_query_subdevice_caps_args; return subdevice; }