| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321 |
- // SPDX-License-Identifier: GPL-2.0
- /***************************************************************************
- * copyright : (C) 2001, 2004 by Frank Mori Hess
- ***************************************************************************
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #define dev_fmt pr_fmt
- #include "ibsys.h"
- #include <linux/module.h>
- #include <linux/wait.h>
- #include <linux/list.h>
- #include <linux/fs.h>
- #include <linux/pci.h>
- #include <linux/device.h>
- #include <linux/init.h>
- #include <linux/string.h>
- #include <linux/vmalloc.h>
- #include <linux/fcntl.h>
- #include <linux/kmod.h>
- #include <linux/uaccess.h>
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("GPIB base support");
- MODULE_ALIAS_CHARDEV_MAJOR(GPIB_CODE);
- static int board_type_ioctl(struct gpib_file_private *file_priv,
- struct gpib_board *board, unsigned long arg);
- static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
- unsigned long arg);
- static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
- unsigned long arg);
- static int command_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
- unsigned long arg);
- static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg);
- static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg);
- static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg);
- static int wait_ioctl(struct gpib_file_private *file_priv,
- struct gpib_board *board, unsigned long arg);
- static int parallel_poll_ioctl(struct gpib_board *board, unsigned long arg);
- static int online_ioctl(struct gpib_board *board, unsigned long arg);
- static int remote_enable_ioctl(struct gpib_board *board, unsigned long arg);
- static int take_control_ioctl(struct gpib_board *board, unsigned long arg);
- static int line_status_ioctl(struct gpib_board *board, unsigned long arg);
- static int pad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg);
- static int sad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg);
- static int eos_ioctl(struct gpib_board *board, unsigned long arg);
- static int request_service_ioctl(struct gpib_board *board, unsigned long arg);
- static int request_service2_ioctl(struct gpib_board *board, unsigned long arg);
- static int iobase_ioctl(struct gpib_board_config *config, unsigned long arg);
- static int irq_ioctl(struct gpib_board_config *config, unsigned long arg);
- static int dma_ioctl(struct gpib_board_config *config, unsigned long arg);
- static int autospoll_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg);
- static int mutex_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg);
- static int timeout_ioctl(struct gpib_board *board, unsigned long arg);
- static int status_bytes_ioctl(struct gpib_board *board, unsigned long arg);
- static int board_info_ioctl(const struct gpib_board *board, unsigned long arg);
- static int ppc_ioctl(struct gpib_board *board, unsigned long arg);
- static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg);
- static int get_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg);
- static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg);
- static int interface_clear_ioctl(struct gpib_board *board, unsigned long arg);
- static int select_pci_ioctl(struct gpib_board_config *config, unsigned long arg);
- static int select_device_path_ioctl(struct gpib_board_config *config, unsigned long arg);
- static int event_ioctl(struct gpib_board *board, unsigned long arg);
- static int request_system_control_ioctl(struct gpib_board *board, unsigned long arg);
- static int t1_delay_ioctl(struct gpib_board *board, unsigned long arg);
- static int cleanup_open_devices(struct gpib_file_private *file_priv, struct gpib_board *board);
- static int pop_gpib_event_nolock(struct gpib_board *board,
- struct gpib_event_queue *queue, short *event_type);
- /*
- * Timer functions
- */
- /* Watchdog timeout routine */
- static void watchdog_timeout(struct timer_list *t)
- {
- struct gpib_board *board = timer_container_of(board, t, timer);
- set_bit(TIMO_NUM, &board->status);
- wake_up_interruptible(&board->wait);
- }
- /* install timer interrupt handler */
- void os_start_timer(struct gpib_board *board, unsigned int usec_timeout)
- /* Starts the timeout task */
- {
- if (timer_pending(&board->timer)) {
- dev_err(board->gpib_dev, "bug! timer already running?\n");
- return;
- }
- clear_bit(TIMO_NUM, &board->status);
- if (usec_timeout > 0) {
- board->timer.function = watchdog_timeout;
- /* set number of ticks */
- mod_timer(&board->timer, jiffies + usec_to_jiffies(usec_timeout));
- }
- }
- void os_remove_timer(struct gpib_board *board)
- /* Removes the timeout task */
- {
- if (timer_pending(&board->timer))
- timer_delete_sync(&board->timer);
- }
- int io_timed_out(struct gpib_board *board)
- {
- if (test_bit(TIMO_NUM, &board->status))
- return 1;
- return 0;
- }
- /*
- * this is a function instead of a constant because of Suse
- * defining HZ to be a function call to get_hz()
- */
- static inline int pseudo_irq_period(void)
- {
- return (HZ + 99) / 100;
- }
- static void pseudo_irq_handler(struct timer_list *t)
- {
- struct gpib_pseudo_irq *pseudo_irq = timer_container_of(pseudo_irq, t,
- timer);
- if (pseudo_irq->handler)
- pseudo_irq->handler(0, pseudo_irq->board);
- else
- pr_err("gpib: bug! pseudo_irq.handler is NULL\n");
- if (atomic_read(&pseudo_irq->active))
- mod_timer(&pseudo_irq->timer, jiffies + pseudo_irq_period());
- }
- int gpib_request_pseudo_irq(struct gpib_board *board, irqreturn_t (*handler)(int, void *))
- {
- if (timer_pending(&board->pseudo_irq.timer) || board->pseudo_irq.handler) {
- dev_err(board->gpib_dev, "only one pseudo interrupt per board allowed\n");
- return -1;
- }
- board->pseudo_irq.handler = handler;
- board->pseudo_irq.timer.function = pseudo_irq_handler;
- board->pseudo_irq.board = board;
- atomic_set(&board->pseudo_irq.active, 1);
- mod_timer(&board->pseudo_irq.timer, jiffies + pseudo_irq_period());
- return 0;
- }
- EXPORT_SYMBOL(gpib_request_pseudo_irq);
- void gpib_free_pseudo_irq(struct gpib_board *board)
- {
- atomic_set(&board->pseudo_irq.active, 0);
- timer_delete_sync(&board->pseudo_irq.timer);
- board->pseudo_irq.handler = NULL;
- }
- EXPORT_SYMBOL(gpib_free_pseudo_irq);
- static const unsigned int serial_timeout = 1000000;
- unsigned int num_status_bytes(const struct gpib_status_queue *dev)
- {
- if (!dev)
- return 0;
- return dev->num_status_bytes;
- }
- // push status byte onto back of status byte fifo
- int push_status_byte(struct gpib_board *board, struct gpib_status_queue *device, u8 poll_byte)
- {
- struct list_head *head = &device->status_bytes;
- struct gpib_status_byte *status;
- static const unsigned int max_num_status_bytes = 1024;
- int retval;
- if (num_status_bytes(device) >= max_num_status_bytes) {
- u8 lost_byte;
- device->dropped_byte = 1;
- retval = pop_status_byte(board, device, &lost_byte);
- if (retval < 0)
- return retval;
- }
- status = kmalloc_obj(*status);
- if (!status)
- return -ENOMEM;
- INIT_LIST_HEAD(&status->list);
- status->poll_byte = poll_byte;
- list_add_tail(&status->list, head);
- device->num_status_bytes++;
- dev_dbg(board->gpib_dev, "pushed status byte 0x%x, %i in queue\n",
- (int)poll_byte, num_status_bytes(device));
- return 0;
- }
- // pop status byte from front of status byte fifo
- int pop_status_byte(struct gpib_board *board, struct gpib_status_queue *device, u8 *poll_byte)
- {
- struct list_head *head = &device->status_bytes;
- struct list_head *front = head->next;
- struct gpib_status_byte *status;
- if (num_status_bytes(device) == 0)
- return -EIO;
- if (front == head)
- return -EIO;
- if (device->dropped_byte) {
- device->dropped_byte = 0;
- return -EPIPE;
- }
- status = list_entry(front, struct gpib_status_byte, list);
- *poll_byte = status->poll_byte;
- list_del(front);
- kfree(status);
- device->num_status_bytes--;
- dev_dbg(board->gpib_dev, "popped status byte 0x%x, %i in queue\n",
- (int)*poll_byte, num_status_bytes(device));
- return 0;
- }
- struct gpib_status_queue *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad)
- {
- struct gpib_status_queue *device;
- struct list_head *list_ptr;
- const struct list_head *head = &board->device_list;
- for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
- device = list_entry(list_ptr, struct gpib_status_queue, list);
- if (gpib_address_equal(device->pad, device->sad, pad, sad))
- return device;
- }
- return NULL;
- }
- int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, u8 *poll_byte)
- {
- struct gpib_status_queue *device;
- device = get_gpib_status_queue(board, pad, sad);
- if (num_status_bytes(device))
- return pop_status_byte(board, device, poll_byte);
- else
- return dvrsp(board, pad, sad, usec_timeout, poll_byte);
- }
- int autopoll_all_devices(struct gpib_board *board)
- {
- int retval;
- if (mutex_lock_interruptible(&board->user_mutex))
- return -ERESTARTSYS;
- if (mutex_lock_interruptible(&board->big_gpib_mutex)) {
- mutex_unlock(&board->user_mutex);
- return -ERESTARTSYS;
- }
- dev_dbg(board->gpib_dev, "autopoll has board lock\n");
- retval = serial_poll_all(board, serial_timeout);
- if (retval < 0) {
- mutex_unlock(&board->big_gpib_mutex);
- mutex_unlock(&board->user_mutex);
- return retval;
- }
- dev_dbg(board->gpib_dev, "complete\n");
- /*
- * need to wake wait queue in case someone is
- * waiting on RQS
- */
- wake_up_interruptible(&board->wait);
- mutex_unlock(&board->big_gpib_mutex);
- mutex_unlock(&board->user_mutex);
- return retval;
- }
- static int setup_serial_poll(struct gpib_board *board, unsigned int usec_timeout)
- {
- u8 cmd_string[8];
- int i;
- size_t bytes_written;
- int ret;
- os_start_timer(board, usec_timeout);
- ret = ibcac(board, 1, 1);
- if (ret < 0) {
- os_remove_timer(board);
- return ret;
- }
- i = 0;
- cmd_string[i++] = UNL;
- cmd_string[i++] = MLA(board->pad); /* controller's listen address */
- if (board->sad >= 0)
- cmd_string[i++] = MSA(board->sad);
- cmd_string[i++] = SPE; // serial poll enable
- ret = board->interface->command(board, cmd_string, i, &bytes_written);
- if (ret < 0 || bytes_written < i) {
- dev_dbg(board->gpib_dev, "failed to setup serial poll\n");
- os_remove_timer(board);
- return -EIO;
- }
- os_remove_timer(board);
- return 0;
- }
- static int read_serial_poll_byte(struct gpib_board *board, unsigned int pad,
- int sad, unsigned int usec_timeout, u8 *result)
- {
- u8 cmd_string[8];
- int end_flag;
- int ret;
- int i;
- size_t nbytes;
- dev_dbg(board->gpib_dev, "entering pad=%i sad=%i\n", pad, sad);
- os_start_timer(board, usec_timeout);
- ret = ibcac(board, 1, 1);
- if (ret < 0) {
- os_remove_timer(board);
- return ret;
- }
- i = 0;
- // send talk address
- cmd_string[i++] = MTA(pad);
- if (sad >= 0)
- cmd_string[i++] = MSA(sad);
- ret = board->interface->command(board, cmd_string, i, &nbytes);
- if (ret < 0 || nbytes < i) {
- dev_err(board->gpib_dev, "failed to setup serial poll\n");
- os_remove_timer(board);
- return -EIO;
- }
- ibgts(board);
- // read poll result
- ret = board->interface->read(board, result, 1, &end_flag, &nbytes);
- if (ret < 0 || nbytes < 1) {
- dev_err(board->gpib_dev, "serial poll failed\n");
- os_remove_timer(board);
- return -EIO;
- }
- os_remove_timer(board);
- return 0;
- }
- static int cleanup_serial_poll(struct gpib_board *board, unsigned int usec_timeout)
- {
- u8 cmd_string[8];
- int ret;
- size_t bytes_written;
- os_start_timer(board, usec_timeout);
- ret = ibcac(board, 1, 1);
- if (ret < 0) {
- os_remove_timer(board);
- return ret;
- }
- cmd_string[0] = SPD; /* disable serial poll bytes */
- cmd_string[1] = UNT;
- ret = board->interface->command(board, cmd_string, 2, &bytes_written);
- if (ret < 0 || bytes_written < 2) {
- dev_err(board->gpib_dev, "failed to disable serial poll\n");
- os_remove_timer(board);
- return -EIO;
- }
- os_remove_timer(board);
- return 0;
- }
- static int serial_poll_single(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, u8 *result)
- {
- int retval, cleanup_retval;
- retval = setup_serial_poll(board, usec_timeout);
- if (retval < 0)
- return retval;
- retval = read_serial_poll_byte(board, pad, sad, usec_timeout, result);
- cleanup_retval = cleanup_serial_poll(board, usec_timeout);
- if (retval < 0)
- return retval;
- if (cleanup_retval < 0)
- return retval;
- return 0;
- }
- int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout)
- {
- int retval = 0;
- struct list_head *cur;
- const struct list_head *head = NULL;
- struct gpib_status_queue *device;
- u8 result;
- unsigned int num_bytes = 0;
- head = &board->device_list;
- if (head->next == head)
- return 0;
- retval = setup_serial_poll(board, usec_timeout);
- if (retval < 0)
- return retval;
- for (cur = head->next; cur != head; cur = cur->next) {
- device = list_entry(cur, struct gpib_status_queue, list);
- retval = read_serial_poll_byte(board,
- device->pad, device->sad, usec_timeout, &result);
- if (retval < 0)
- continue;
- if (result & request_service_bit) {
- retval = push_status_byte(board, device, result);
- if (retval < 0)
- continue;
- num_bytes++;
- }
- }
- retval = cleanup_serial_poll(board, usec_timeout);
- if (retval < 0)
- return retval;
- return num_bytes;
- }
- /*
- * DVRSP
- * This function performs a serial poll of the device with primary
- * address pad and secondary address sad. If the device has no
- * secondary address, pass a negative number in for this argument. At the
- * end of a successful serial poll the response is returned in result.
- * SPD and UNT are sent at the completion of the poll.
- */
- int dvrsp(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, u8 *result)
- {
- int status = ibstatus(board);
- int retval;
- if ((status & CIC) == 0) {
- dev_err(board->gpib_dev, "not CIC during serial poll\n");
- return -1;
- }
- if (pad > MAX_GPIB_PRIMARY_ADDRESS || sad > MAX_GPIB_SECONDARY_ADDRESS || sad < -1) {
- dev_err(board->gpib_dev, "bad address for serial poll");
- return -1;
- }
- retval = serial_poll_single(board, pad, sad, usec_timeout, result);
- if (io_timed_out(board))
- retval = -ETIMEDOUT;
- return retval;
- }
- static struct gpib_descriptor *handle_to_descriptor(const struct gpib_file_private *file_priv,
- int handle)
- {
- if (handle < 0 || handle >= GPIB_MAX_NUM_DESCRIPTORS) {
- pr_err("gpib: invalid handle %i\n", handle);
- return NULL;
- }
- return file_priv->descriptors[handle];
- }
- static int init_gpib_file_private(struct gpib_file_private *priv)
- {
- memset(priv, 0, sizeof(*priv));
- atomic_set(&priv->holding_mutex, 0);
- priv->descriptors[0] = kmalloc_obj(struct gpib_descriptor);
- if (!priv->descriptors[0]) {
- pr_err("gpib: failed to allocate default board descriptor\n");
- return -ENOMEM;
- }
- init_gpib_descriptor(priv->descriptors[0]);
- priv->descriptors[0]->is_board = 1;
- mutex_init(&priv->descriptors_mutex);
- return 0;
- }
- int ibopen(struct inode *inode, struct file *filep)
- {
- unsigned int minor = iminor(inode);
- struct gpib_board *board;
- struct gpib_file_private *priv;
- if (minor >= GPIB_MAX_NUM_BOARDS) {
- pr_err("gpib: invalid minor number of device file\n");
- return -ENXIO;
- }
- board = &board_array[minor];
- filep->private_data = kmalloc_obj(struct gpib_file_private);
- if (!filep->private_data)
- return -ENOMEM;
- priv = filep->private_data;
- init_gpib_file_private((struct gpib_file_private *)filep->private_data);
- if (board->use_count == 0) {
- int retval;
- retval = request_module("gpib%i", minor);
- if (retval)
- dev_dbg(board->gpib_dev, "request module returned %i\n", retval);
- }
- if (board->interface) {
- if (!try_module_get(board->provider_module)) {
- dev_err(board->gpib_dev, "try_module_get() failed\n");
- return -EIO;
- }
- board->use_count++;
- priv->got_module = 1;
- }
- return 0;
- }
- int ibclose(struct inode *inode, struct file *filep)
- {
- unsigned int minor = iminor(inode);
- struct gpib_board *board;
- struct gpib_file_private *priv = filep->private_data;
- struct gpib_descriptor *desc;
- if (minor >= GPIB_MAX_NUM_BOARDS) {
- pr_err("gpib: invalid minor number of device file\n");
- return -ENODEV;
- }
- board = &board_array[minor];
- if (priv) {
- desc = handle_to_descriptor(priv, 0);
- if (desc) {
- if (desc->autopoll_enabled) {
- dev_dbg(board->gpib_dev, "decrementing autospollers\n");
- if (board->autospollers > 0)
- board->autospollers--;
- else
- dev_err(board->gpib_dev,
- "Attempt to decrement zero autospollers\n");
- }
- } else {
- dev_err(board->gpib_dev, "Unexpected null gpib_descriptor\n");
- }
- cleanup_open_devices(priv, board);
- if (atomic_read(&priv->holding_mutex))
- mutex_unlock(&board->user_mutex);
- if (priv->got_module && board->use_count) {
- module_put(board->provider_module);
- --board->use_count;
- }
- kfree(filep->private_data);
- filep->private_data = NULL;
- }
- return 0;
- }
- long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
- {
- unsigned int minor = iminor(file_inode(filep));
- struct gpib_board *board;
- struct gpib_file_private *file_priv = filep->private_data;
- long retval = -ENOTTY;
- if (minor >= GPIB_MAX_NUM_BOARDS) {
- pr_err("gpib: invalid minor number of device file\n");
- return -ENODEV;
- }
- board = &board_array[minor];
- if (mutex_lock_interruptible(&board->big_gpib_mutex))
- return -ERESTARTSYS;
- dev_dbg(board->gpib_dev, "ioctl %d, interface=%s, use=%d, onl=%d\n",
- cmd & 0xff,
- board->interface ? board->interface->name : "",
- board->use_count,
- board->online);
- switch (cmd) {
- case CFCBOARDTYPE:
- retval = board_type_ioctl(file_priv, board, arg);
- goto done;
- case IBONL:
- retval = online_ioctl(board, arg);
- goto done;
- default:
- break;
- }
- if (!board->interface) {
- dev_err(board->gpib_dev, "no gpib board configured\n");
- retval = -ENODEV;
- goto done;
- }
- if (file_priv->got_module == 0) {
- if (!try_module_get(board->provider_module)) {
- dev_err(board->gpib_dev, "try_module_get() failed\n");
- retval = -EIO;
- goto done;
- }
- file_priv->got_module = 1;
- board->use_count++;
- }
- switch (cmd) {
- case CFCBASE:
- retval = iobase_ioctl(&board->config, arg);
- goto done;
- case CFCIRQ:
- retval = irq_ioctl(&board->config, arg);
- goto done;
- case CFCDMA:
- retval = dma_ioctl(&board->config, arg);
- goto done;
- case IBAUTOSPOLL:
- retval = autospoll_ioctl(board, file_priv, arg);
- goto done;
- case IBBOARD_INFO:
- retval = board_info_ioctl(board, arg);
- goto done;
- case IBMUTEX:
- /*
- * Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex
- * to maintain consistent locking order
- */
- mutex_unlock(&board->big_gpib_mutex);
- return mutex_ioctl(board, file_priv, arg);
- case IBPAD:
- retval = pad_ioctl(board, file_priv, arg);
- goto done;
- case IBSAD:
- retval = sad_ioctl(board, file_priv, arg);
- goto done;
- case IBSELECT_PCI:
- retval = select_pci_ioctl(&board->config, arg);
- goto done;
- case IBSELECT_DEVICE_PATH:
- retval = select_device_path_ioctl(&board->config, arg);
- goto done;
- default:
- break;
- }
- if (!board->online) {
- retval = -EINVAL;
- goto done;
- }
- switch (cmd) {
- case IBEVENT:
- retval = event_ioctl(board, arg);
- goto done;
- case IBCLOSEDEV:
- retval = close_dev_ioctl(filep, board, arg);
- goto done;
- case IBOPENDEV:
- retval = open_dev_ioctl(filep, board, arg);
- goto done;
- case IBSPOLL_BYTES:
- retval = status_bytes_ioctl(board, arg);
- goto done;
- case IBWAIT:
- retval = wait_ioctl(file_priv, board, arg);
- if (retval == -ERESTARTSYS)
- return retval;
- goto done;
- case IBLINES:
- retval = line_status_ioctl(board, arg);
- goto done;
- case IBLOC:
- board->interface->return_to_local(board);
- retval = 0;
- goto done;
- default:
- break;
- }
- spin_lock(&board->locking_pid_spinlock);
- if (current->pid != board->locking_pid) {
- spin_unlock(&board->locking_pid_spinlock);
- retval = -EPERM;
- goto done;
- }
- spin_unlock(&board->locking_pid_spinlock);
- switch (cmd) {
- case IB_T1_DELAY:
- retval = t1_delay_ioctl(board, arg);
- goto done;
- case IBCAC:
- retval = take_control_ioctl(board, arg);
- goto done;
- case IBCMD:
- /*
- * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
- * before we call them.
- */
- mutex_unlock(&board->big_gpib_mutex);
- return command_ioctl(file_priv, board, arg);
- case IBEOS:
- retval = eos_ioctl(board, arg);
- goto done;
- case IBGTS:
- retval = ibgts(board);
- goto done;
- case IBPPC:
- retval = ppc_ioctl(board, arg);
- goto done;
- case IBPP2_SET:
- retval = set_local_ppoll_mode_ioctl(board, arg);
- goto done;
- case IBPP2_GET:
- retval = get_local_ppoll_mode_ioctl(board, arg);
- goto done;
- case IBQUERY_BOARD_RSV:
- retval = query_board_rsv_ioctl(board, arg);
- goto done;
- case IBRD:
- /*
- * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
- * before we call them.
- */
- mutex_unlock(&board->big_gpib_mutex);
- return read_ioctl(file_priv, board, arg);
- case IBRPP:
- retval = parallel_poll_ioctl(board, arg);
- goto done;
- case IBRSC:
- retval = request_system_control_ioctl(board, arg);
- goto done;
- case IBRSP:
- retval = serial_poll_ioctl(board, arg);
- goto done;
- case IBRSV:
- retval = request_service_ioctl(board, arg);
- goto done;
- case IBRSV2:
- retval = request_service2_ioctl(board, arg);
- goto done;
- case IBSIC:
- retval = interface_clear_ioctl(board, arg);
- goto done;
- case IBSRE:
- retval = remote_enable_ioctl(board, arg);
- goto done;
- case IBTMO:
- retval = timeout_ioctl(board, arg);
- goto done;
- case IBWRT:
- /*
- * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
- * before we call them.
- */
- mutex_unlock(&board->big_gpib_mutex);
- return write_ioctl(file_priv, board, arg);
- default:
- retval = -ENOTTY;
- goto done;
- }
- done:
- mutex_unlock(&board->big_gpib_mutex);
- dev_dbg(board->gpib_dev, "ioctl done status = 0x%lx\n", board->status);
- return retval;
- }
- static int board_type_ioctl(struct gpib_file_private *file_priv,
- struct gpib_board *board, unsigned long arg)
- {
- struct list_head *list_ptr;
- struct gpib_board_type_ioctl cmd;
- int retval;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (board->online)
- return -EBUSY;
- retval = copy_from_user(&cmd, (void __user *)arg,
- sizeof(struct gpib_board_type_ioctl));
- if (retval)
- return -EFAULT;
- for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers;
- list_ptr = list_ptr->next) {
- struct gpib_interface_list *entry;
- entry = list_entry(list_ptr, struct gpib_interface_list, list);
- if (strcmp(entry->interface->name, cmd.name) == 0) {
- int i;
- int had_module = file_priv->got_module;
- if (board->use_count) {
- for (i = 0; i < board->use_count; ++i)
- module_put(board->provider_module);
- board->interface = NULL;
- file_priv->got_module = 0;
- }
- board->interface = entry->interface;
- board->provider_module = entry->module;
- for (i = 0; i < board->use_count; ++i) {
- if (!try_module_get(entry->module)) {
- board->use_count = i;
- return -EIO;
- }
- }
- if (had_module == 0) {
- if (!try_module_get(entry->module))
- return -EIO;
- ++board->use_count;
- }
- file_priv->got_module = 1;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
- unsigned long arg)
- {
- struct gpib_read_write_ioctl read_cmd;
- u8 __user *userbuf;
- unsigned long remain;
- int end_flag = 0;
- int retval;
- ssize_t read_ret = 0;
- struct gpib_descriptor *desc;
- size_t nbytes;
- retval = copy_from_user(&read_cmd, (void __user *)arg, sizeof(read_cmd));
- if (retval)
- return -EFAULT;
- if (read_cmd.completed_transfer_count > read_cmd.requested_transfer_count)
- return -EINVAL;
- if (WARN_ON_ONCE(sizeof(userbuf) > sizeof(read_cmd.buffer_ptr)))
- return -EFAULT;
- userbuf = (u8 __user *)(unsigned long)read_cmd.buffer_ptr;
- userbuf += read_cmd.completed_transfer_count;
- remain = read_cmd.requested_transfer_count - read_cmd.completed_transfer_count;
- /* Check write access to buffer */
- if (!access_ok(userbuf, remain))
- return -EFAULT;
- /* Lock descriptors to prevent concurrent close from freeing descriptor */
- if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
- return -ERESTARTSYS;
- desc = handle_to_descriptor(file_priv, read_cmd.handle);
- if (!desc) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -EINVAL;
- }
- atomic_inc(&desc->descriptor_busy);
- mutex_unlock(&file_priv->descriptors_mutex);
- atomic_set(&desc->io_in_progress, 1);
- /* Read buffer loads till we fill the user supplied buffer */
- while (remain > 0 && end_flag == 0) {
- nbytes = 0;
- read_ret = ibrd(board, board->buffer, (board->buffer_length < remain) ?
- board->buffer_length : remain, &end_flag, &nbytes);
- if (nbytes == 0)
- break;
- retval = copy_to_user(userbuf, board->buffer, nbytes);
- if (retval) {
- retval = -EFAULT;
- break;
- }
- remain -= nbytes;
- userbuf += nbytes;
- if (read_ret < 0)
- break;
- }
- read_cmd.completed_transfer_count = read_cmd.requested_transfer_count - remain;
- read_cmd.end = end_flag;
- /*
- * suppress errors (for example due to timeout or interruption by device clear)
- * if all bytes got sent. This prevents races that can occur in the various drivers
- * if a device receives a device clear immediately after a transfer completes and
- * the driver code wasn't careful enough to handle that case.
- */
- if (remain == 0 || end_flag)
- read_ret = 0;
- if (retval == 0)
- retval = copy_to_user((void __user *)arg, &read_cmd, sizeof(read_cmd));
- atomic_set(&desc->io_in_progress, 0);
- atomic_dec(&desc->descriptor_busy);
- wake_up_interruptible(&board->wait);
- if (retval)
- return -EFAULT;
- return read_ret;
- }
- static int command_ioctl(struct gpib_file_private *file_priv,
- struct gpib_board *board, unsigned long arg)
- {
- struct gpib_read_write_ioctl cmd;
- u8 __user *userbuf;
- unsigned long remain;
- int retval;
- int fault = 0;
- struct gpib_descriptor *desc;
- size_t bytes_written;
- int no_clear_io_in_prog;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- if (cmd.completed_transfer_count > cmd.requested_transfer_count)
- return -EINVAL;
- userbuf = (u8 __user *)(unsigned long)cmd.buffer_ptr;
- userbuf += cmd.completed_transfer_count;
- no_clear_io_in_prog = cmd.end;
- cmd.end = 0;
- remain = cmd.requested_transfer_count - cmd.completed_transfer_count;
- /* Check read access to buffer */
- if (!access_ok(userbuf, remain))
- return -EFAULT;
- /* Lock descriptors to prevent concurrent close from freeing descriptor */
- if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
- return -ERESTARTSYS;
- desc = handle_to_descriptor(file_priv, cmd.handle);
- if (!desc) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -EINVAL;
- }
- atomic_inc(&desc->descriptor_busy);
- mutex_unlock(&file_priv->descriptors_mutex);
- /*
- * Write buffer loads till we empty the user supplied buffer.
- * Call drivers at least once, even if remain is zero, in
- * order to allow them to insure previous commands were
- * completely finished, in the case of a restarted ioctl.
- */
- atomic_set(&desc->io_in_progress, 1);
- do {
- fault = copy_from_user(board->buffer, userbuf, (board->buffer_length < remain) ?
- board->buffer_length : remain);
- if (fault) {
- retval = -EFAULT;
- bytes_written = 0;
- } else {
- retval = ibcmd(board, board->buffer, (board->buffer_length < remain) ?
- board->buffer_length : remain, &bytes_written);
- }
- remain -= bytes_written;
- userbuf += bytes_written;
- if (retval < 0) {
- atomic_set(&desc->io_in_progress, 0);
- atomic_dec(&desc->descriptor_busy);
- wake_up_interruptible(&board->wait);
- break;
- }
- } while (remain > 0);
- cmd.completed_transfer_count = cmd.requested_transfer_count - remain;
- if (fault == 0)
- fault = copy_to_user((void __user *)arg, &cmd, sizeof(cmd));
- /*
- * no_clear_io_in_prog (cmd.end) is true when io_in_progress should
- * not be set to zero because the cmd in progress is the address setup
- * operation for an async read or write. This causes CMPL not to be set
- * in general_ibstatus until the async read or write completes.
- */
- if (!no_clear_io_in_prog || fault)
- atomic_set(&desc->io_in_progress, 0);
- atomic_dec(&desc->descriptor_busy);
- wake_up_interruptible(&board->wait);
- if (fault)
- return -EFAULT;
- return retval;
- }
- static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
- unsigned long arg)
- {
- struct gpib_read_write_ioctl write_cmd;
- u8 __user *userbuf;
- unsigned long remain;
- int retval = 0;
- int fault;
- struct gpib_descriptor *desc;
- fault = copy_from_user(&write_cmd, (void __user *)arg, sizeof(write_cmd));
- if (fault)
- return -EFAULT;
- if (write_cmd.completed_transfer_count > write_cmd.requested_transfer_count)
- return -EINVAL;
- userbuf = (u8 __user *)(unsigned long)write_cmd.buffer_ptr;
- userbuf += write_cmd.completed_transfer_count;
- remain = write_cmd.requested_transfer_count - write_cmd.completed_transfer_count;
- /* Check read access to buffer */
- if (!access_ok(userbuf, remain))
- return -EFAULT;
- /* Lock descriptors to prevent concurrent close from freeing descriptor */
- if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
- return -ERESTARTSYS;
- desc = handle_to_descriptor(file_priv, write_cmd.handle);
- if (!desc) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -EINVAL;
- }
- atomic_inc(&desc->descriptor_busy);
- mutex_unlock(&file_priv->descriptors_mutex);
- atomic_set(&desc->io_in_progress, 1);
- /* Write buffer loads till we empty the user supplied buffer */
- while (remain > 0) {
- int send_eoi;
- size_t bytes_written = 0;
- send_eoi = remain <= board->buffer_length && write_cmd.end;
- fault = copy_from_user(board->buffer, userbuf, (board->buffer_length < remain) ?
- board->buffer_length : remain);
- if (fault) {
- retval = -EFAULT;
- break;
- }
- retval = ibwrt(board, board->buffer, (board->buffer_length < remain) ?
- board->buffer_length : remain, send_eoi, &bytes_written);
- remain -= bytes_written;
- userbuf += bytes_written;
- if (retval < 0)
- break;
- }
- write_cmd.completed_transfer_count = write_cmd.requested_transfer_count - remain;
- /*
- * suppress errors (for example due to timeout or interruption by device clear)
- * if all bytes got sent. This prevents races that can occur in the various drivers
- * if a device receives a device clear immediately after a transfer completes and
- * the driver code wasn't careful enough to handle that case.
- */
- if (remain == 0)
- retval = 0;
- if (fault == 0)
- fault = copy_to_user((void __user *)arg, &write_cmd, sizeof(write_cmd));
- atomic_set(&desc->io_in_progress, 0);
- atomic_dec(&desc->descriptor_busy);
- wake_up_interruptible(&board->wait);
- if (fault)
- return -EFAULT;
- return retval;
- }
- static int status_bytes_ioctl(struct gpib_board *board, unsigned long arg)
- {
- struct gpib_status_queue *device;
- struct gpib_spoll_bytes_ioctl cmd;
- int retval;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- device = get_gpib_status_queue(board, cmd.pad, cmd.sad);
- if (!device)
- cmd.num_bytes = 0;
- else
- cmd.num_bytes = num_status_bytes(device);
- retval = copy_to_user((void __user *)arg, &cmd, sizeof(cmd));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int increment_open_device_count(struct gpib_board *board, struct list_head *head,
- unsigned int pad, int sad)
- {
- struct list_head *list_ptr;
- struct gpib_status_queue *device;
- /*
- * first see if address has already been opened, then increment
- * open count
- */
- for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
- device = list_entry(list_ptr, struct gpib_status_queue, list);
- if (gpib_address_equal(device->pad, device->sad, pad, sad)) {
- dev_dbg(board->gpib_dev, "incrementing open count for pad %i, sad %i\n",
- device->pad, device->sad);
- device->reference_count++;
- return 0;
- }
- }
- /* otherwise we need to allocate a new struct gpib_status_queue */
- device = kmalloc_obj(struct gpib_status_queue, GFP_ATOMIC);
- if (!device)
- return -ENOMEM;
- init_gpib_status_queue(device);
- device->pad = pad;
- device->sad = sad;
- device->reference_count = 1;
- list_add(&device->list, head);
- dev_dbg(board->gpib_dev, "opened pad %i, sad %i\n", device->pad, device->sad);
- return 0;
- }
- static int subtract_open_device_count(struct gpib_board *board, struct list_head *head,
- unsigned int pad, int sad, unsigned int count)
- {
- struct gpib_status_queue *device;
- struct list_head *list_ptr;
- for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
- device = list_entry(list_ptr, struct gpib_status_queue, list);
- if (gpib_address_equal(device->pad, device->sad, pad, sad)) {
- dev_dbg(board->gpib_dev, "decrementing open count for pad %i, sad %i\n",
- device->pad, device->sad);
- if (count > device->reference_count) {
- dev_err(board->gpib_dev, "bug! in %s()\n", __func__);
- return -EINVAL;
- }
- device->reference_count -= count;
- if (device->reference_count == 0) {
- dev_dbg(board->gpib_dev, "closing pad %i, sad %i\n",
- device->pad, device->sad);
- list_del(list_ptr);
- kfree(device);
- }
- return 0;
- }
- }
- dev_err(board->gpib_dev, "bug! tried to close address that was never opened!\n");
- return -EINVAL;
- }
- static inline int decrement_open_device_count(struct gpib_board *board, struct list_head *head,
- unsigned int pad, int sad)
- {
- return subtract_open_device_count(board, head, pad, sad, 1);
- }
- static int cleanup_open_devices(struct gpib_file_private *file_priv, struct gpib_board *board)
- {
- int retval = 0;
- int i;
- for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++) {
- struct gpib_descriptor *desc;
- desc = file_priv->descriptors[i];
- if (!desc)
- continue;
- if (desc->is_board == 0) {
- retval = decrement_open_device_count(board, &board->device_list, desc->pad,
- desc->sad);
- if (retval < 0)
- return retval;
- }
- kfree(desc);
- file_priv->descriptors[i] = NULL;
- }
- return 0;
- }
- static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg)
- {
- struct gpib_open_dev_ioctl open_dev_cmd;
- int retval;
- struct gpib_file_private *file_priv = filep->private_data;
- int i;
- retval = copy_from_user(&open_dev_cmd, (void __user *)arg, sizeof(open_dev_cmd));
- if (retval)
- return -EFAULT;
- if (mutex_lock_interruptible(&file_priv->descriptors_mutex))
- return -ERESTARTSYS;
- for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++)
- if (!file_priv->descriptors[i])
- break;
- if (i == GPIB_MAX_NUM_DESCRIPTORS) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -ERANGE;
- }
- file_priv->descriptors[i] = kmalloc_obj(struct gpib_descriptor);
- if (!file_priv->descriptors[i]) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -ENOMEM;
- }
- init_gpib_descriptor(file_priv->descriptors[i]);
- file_priv->descriptors[i]->pad = open_dev_cmd.pad;
- file_priv->descriptors[i]->sad = open_dev_cmd.sad;
- file_priv->descriptors[i]->is_board = open_dev_cmd.is_board;
- mutex_unlock(&file_priv->descriptors_mutex);
- retval = increment_open_device_count(board, &board->device_list, open_dev_cmd.pad,
- open_dev_cmd.sad);
- if (retval < 0)
- return retval;
- /*
- * clear stuck srq state, since we may be able to find service request on
- * the new device
- */
- atomic_set(&board->stuck_srq, 0);
- open_dev_cmd.handle = i;
- retval = copy_to_user((void __user *)arg, &open_dev_cmd, sizeof(open_dev_cmd));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg)
- {
- struct gpib_close_dev_ioctl cmd;
- struct gpib_file_private *file_priv = filep->private_data;
- struct gpib_descriptor *desc;
- unsigned int pad;
- int sad;
- int retval;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- if (cmd.handle >= GPIB_MAX_NUM_DESCRIPTORS)
- return -EINVAL;
- mutex_lock(&file_priv->descriptors_mutex);
- desc = file_priv->descriptors[cmd.handle];
- if (!desc) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -EINVAL;
- }
- if (atomic_read(&desc->descriptor_busy)) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -EBUSY;
- }
- /* Remove from table while holding lock to prevent new IO from starting */
- file_priv->descriptors[cmd.handle] = NULL;
- pad = desc->pad;
- sad = desc->sad;
- mutex_unlock(&file_priv->descriptors_mutex);
- retval = decrement_open_device_count(board, &board->device_list, pad, sad);
- kfree(desc);
- return retval;
- }
- static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg)
- {
- struct gpib_serial_poll_ioctl serial_cmd;
- int retval;
- retval = copy_from_user(&serial_cmd, (void __user *)arg, sizeof(serial_cmd));
- if (retval)
- return -EFAULT;
- retval = get_serial_poll_byte(board, serial_cmd.pad, serial_cmd.sad, board->usec_timeout,
- &serial_cmd.status_byte);
- if (retval < 0)
- return retval;
- retval = copy_to_user((void __user *)arg, &serial_cmd, sizeof(serial_cmd));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int wait_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
- unsigned long arg)
- {
- struct gpib_wait_ioctl wait_cmd;
- int retval;
- struct gpib_descriptor *desc;
- retval = copy_from_user(&wait_cmd, (void __user *)arg, sizeof(wait_cmd));
- if (retval)
- return -EFAULT;
- /*
- * Lock descriptors to prevent concurrent close from freeing
- * descriptor. ibwait() releases big_gpib_mutex when wait_mask
- * is non-zero, so desc must be pinned with descriptor_busy.
- */
- mutex_lock(&file_priv->descriptors_mutex);
- desc = handle_to_descriptor(file_priv, wait_cmd.handle);
- if (!desc) {
- mutex_unlock(&file_priv->descriptors_mutex);
- return -EINVAL;
- }
- atomic_inc(&desc->descriptor_busy);
- mutex_unlock(&file_priv->descriptors_mutex);
- retval = ibwait(board, wait_cmd.wait_mask, wait_cmd.clear_mask,
- wait_cmd.set_mask, &wait_cmd.ibsta, wait_cmd.usec_timeout, desc);
- atomic_dec(&desc->descriptor_busy);
- if (retval < 0)
- return retval;
- retval = copy_to_user((void __user *)arg, &wait_cmd, sizeof(wait_cmd));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int parallel_poll_ioctl(struct gpib_board *board, unsigned long arg)
- {
- u8 poll_byte;
- int retval;
- retval = ibrpp(board, &poll_byte);
- if (retval < 0)
- return retval;
- retval = copy_to_user((void __user *)arg, &poll_byte, sizeof(poll_byte));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int online_ioctl(struct gpib_board *board, unsigned long arg)
- {
- struct gpib_online_ioctl online_cmd;
- int retval;
- void __user *init_data = NULL;
- board->config.init_data = NULL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- retval = copy_from_user(&online_cmd, (void __user *)arg, sizeof(online_cmd));
- if (retval)
- return -EFAULT;
- if (online_cmd.init_data_length > 0) {
- board->config.init_data = vmalloc(online_cmd.init_data_length);
- if (!board->config.init_data)
- return -ENOMEM;
- if (WARN_ON_ONCE(sizeof(init_data) > sizeof(online_cmd.init_data_ptr)))
- return -EFAULT;
- init_data = (void __user *)(unsigned long)(online_cmd.init_data_ptr);
- retval = copy_from_user(board->config.init_data, init_data,
- online_cmd.init_data_length);
- if (retval) {
- vfree(board->config.init_data);
- return -EFAULT;
- }
- board->config.init_data_length = online_cmd.init_data_length;
- } else {
- board->config.init_data = NULL;
- board->config.init_data_length = 0;
- }
- if (online_cmd.online)
- retval = ibonline(board);
- else
- retval = iboffline(board);
- if (board->config.init_data) {
- vfree(board->config.init_data);
- board->config.init_data = NULL;
- board->config.init_data_length = 0;
- }
- return retval;
- }
- static int remote_enable_ioctl(struct gpib_board *board, unsigned long arg)
- {
- int enable;
- int retval;
- retval = copy_from_user(&enable, (void __user *)arg, sizeof(enable));
- if (retval)
- return -EFAULT;
- return ibsre(board, enable);
- }
- static int take_control_ioctl(struct gpib_board *board, unsigned long arg)
- {
- int synchronous;
- int retval;
- retval = copy_from_user(&synchronous, (void __user *)arg, sizeof(synchronous));
- if (retval)
- return -EFAULT;
- return ibcac(board, synchronous, 1);
- }
- static int line_status_ioctl(struct gpib_board *board, unsigned long arg)
- {
- short lines;
- int retval;
- retval = iblines(board, &lines);
- if (retval < 0)
- return retval;
- retval = copy_to_user((void __user *)arg, &lines, sizeof(lines));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int pad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg)
- {
- struct gpib_pad_ioctl cmd;
- int retval;
- struct gpib_descriptor *desc;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- desc = handle_to_descriptor(file_priv, cmd.handle);
- if (!desc)
- return -EINVAL;
- if (desc->is_board) {
- retval = ibpad(board, cmd.pad);
- if (retval < 0)
- return retval;
- } else {
- retval = decrement_open_device_count(board, &board->device_list, desc->pad,
- desc->sad);
- if (retval < 0)
- return retval;
- desc->pad = cmd.pad;
- retval = increment_open_device_count(board, &board->device_list, desc->pad,
- desc->sad);
- if (retval < 0)
- return retval;
- }
- return 0;
- }
- static int sad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg)
- {
- struct gpib_sad_ioctl cmd;
- int retval;
- struct gpib_descriptor *desc;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- desc = handle_to_descriptor(file_priv, cmd.handle);
- if (!desc)
- return -EINVAL;
- if (desc->is_board) {
- retval = ibsad(board, cmd.sad);
- if (retval < 0)
- return retval;
- } else {
- retval = decrement_open_device_count(board, &board->device_list, desc->pad,
- desc->sad);
- if (retval < 0)
- return retval;
- desc->sad = cmd.sad;
- retval = increment_open_device_count(board, &board->device_list, desc->pad,
- desc->sad);
- if (retval < 0)
- return retval;
- }
- return 0;
- }
- static int eos_ioctl(struct gpib_board *board, unsigned long arg)
- {
- struct gpib_eos_ioctl eos_cmd;
- int retval;
- retval = copy_from_user(&eos_cmd, (void __user *)arg, sizeof(eos_cmd));
- if (retval)
- return -EFAULT;
- return ibeos(board, eos_cmd.eos, eos_cmd.eos_flags);
- }
- static int request_service_ioctl(struct gpib_board *board, unsigned long arg)
- {
- u8 status_byte;
- int retval;
- retval = copy_from_user(&status_byte, (void __user *)arg, sizeof(status_byte));
- if (retval)
- return -EFAULT;
- return ibrsv2(board, status_byte, status_byte & request_service_bit);
- }
- static int request_service2_ioctl(struct gpib_board *board, unsigned long arg)
- {
- struct gpib_request_service2 request_service2_cmd;
- int retval;
- retval = copy_from_user(&request_service2_cmd, (void __user *)arg,
- sizeof(struct gpib_request_service2));
- if (retval)
- return -EFAULT;
- return ibrsv2(board, request_service2_cmd.status_byte,
- request_service2_cmd.new_reason_for_service);
- }
- static int iobase_ioctl(struct gpib_board_config *config, unsigned long arg)
- {
- u64 base_addr;
- int retval;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- retval = copy_from_user(&base_addr, (void __user *)arg, sizeof(base_addr));
- if (retval)
- return -EFAULT;
- if (WARN_ON_ONCE(sizeof(void *) > sizeof(base_addr)))
- return -EFAULT;
- config->ibbase = base_addr;
- return 0;
- }
- static int irq_ioctl(struct gpib_board_config *config, unsigned long arg)
- {
- unsigned int irq;
- int retval;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- retval = copy_from_user(&irq, (void __user *)arg, sizeof(irq));
- if (retval)
- return -EFAULT;
- config->ibirq = irq;
- return 0;
- }
- static int dma_ioctl(struct gpib_board_config *config, unsigned long arg)
- {
- unsigned int dma_channel;
- int retval;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- retval = copy_from_user(&dma_channel, (void __user *)arg, sizeof(dma_channel));
- if (retval)
- return -EFAULT;
- config->ibdma = dma_channel;
- return 0;
- }
- static int autospoll_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg)
- {
- short enable;
- int retval;
- struct gpib_descriptor *desc;
- retval = copy_from_user(&enable, (void __user *)arg, sizeof(enable));
- if (retval)
- return -EFAULT;
- desc = handle_to_descriptor(file_priv, 0); /* board handle is 0 */
- if (enable) {
- if (!desc->autopoll_enabled) {
- board->autospollers++;
- desc->autopoll_enabled = 1;
- }
- retval = 0;
- } else {
- if (desc->autopoll_enabled) {
- desc->autopoll_enabled = 0;
- if (board->autospollers > 0) {
- board->autospollers--;
- retval = 0;
- } else {
- dev_err(board->gpib_dev,
- "tried to set number of autospollers negative\n");
- retval = -EINVAL;
- }
- } else {
- dev_err(board->gpib_dev, "autopoll disable requested before enable\n");
- retval = -EINVAL;
- }
- }
- return retval;
- }
- static int mutex_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
- unsigned long arg)
- {
- int retval, lock_mutex;
- retval = copy_from_user(&lock_mutex, (void __user *)arg, sizeof(lock_mutex));
- if (retval)
- return -EFAULT;
- if (lock_mutex) {
- retval = mutex_lock_interruptible(&board->user_mutex);
- if (retval)
- return -ERESTARTSYS;
- spin_lock(&board->locking_pid_spinlock);
- board->locking_pid = current->pid;
- spin_unlock(&board->locking_pid_spinlock);
- atomic_set(&file_priv->holding_mutex, 1);
- dev_dbg(board->gpib_dev, "locked board mutex\n");
- } else {
- spin_lock(&board->locking_pid_spinlock);
- if (current->pid != board->locking_pid) {
- dev_err(board->gpib_dev, "bug! pid %i tried to release mutex held by pid %i\n",
- current->pid, board->locking_pid);
- spin_unlock(&board->locking_pid_spinlock);
- return -EPERM;
- }
- board->locking_pid = 0;
- spin_unlock(&board->locking_pid_spinlock);
- atomic_set(&file_priv->holding_mutex, 0);
- mutex_unlock(&board->user_mutex);
- dev_dbg(board->gpib_dev, "unlocked board mutex\n");
- }
- return 0;
- }
- static int timeout_ioctl(struct gpib_board *board, unsigned long arg)
- {
- unsigned int timeout;
- int retval;
- retval = copy_from_user(&timeout, (void __user *)arg, sizeof(timeout));
- if (retval)
- return -EFAULT;
- board->usec_timeout = timeout;
- dev_dbg(board->gpib_dev, "timeout set to %i usec\n", timeout);
- return 0;
- }
- static int ppc_ioctl(struct gpib_board *board, unsigned long arg)
- {
- struct gpib_ppoll_config_ioctl cmd;
- int retval;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- if (cmd.set_ist) {
- board->ist = 1;
- board->interface->parallel_poll_response(board, board->ist);
- } else if (cmd.clear_ist) {
- board->ist = 0;
- board->interface->parallel_poll_response(board, board->ist);
- }
- if (cmd.config) {
- retval = ibppc(board, cmd.config);
- if (retval < 0)
- return retval;
- }
- return 0;
- }
- static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg)
- {
- short cmd;
- int retval;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- if (!board->interface->local_parallel_poll_mode)
- return -ENOENT;
- board->local_ppoll_mode = cmd != 0;
- board->interface->local_parallel_poll_mode(board, board->local_ppoll_mode);
- return 0;
- }
- static int get_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg)
- {
- short cmd;
- int retval;
- cmd = board->local_ppoll_mode;
- retval = copy_to_user((void __user *)arg, &cmd, sizeof(cmd));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg)
- {
- int status;
- int retval;
- status = board->interface->serial_poll_status(board);
- retval = copy_to_user((void __user *)arg, &status, sizeof(status));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int board_info_ioctl(const struct gpib_board *board, unsigned long arg)
- {
- struct gpib_board_info_ioctl info = { };
- int retval;
- info.pad = board->pad;
- info.sad = board->sad;
- info.parallel_poll_configuration = board->parallel_poll_configuration;
- info.is_system_controller = board->master;
- if (board->autospollers)
- info.autopolling = 1;
- else
- info.autopolling = 0;
- info.t1_delay = board->t1_nano_sec;
- info.ist = board->ist;
- info.no_7_bit_eos = board->interface->no_7_bit_eos;
- retval = copy_to_user((void __user *)arg, &info, sizeof(info));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int interface_clear_ioctl(struct gpib_board *board, unsigned long arg)
- {
- unsigned int usec_duration;
- int retval;
- retval = copy_from_user(&usec_duration, (void __user *)arg, sizeof(usec_duration));
- if (retval)
- return -EFAULT;
- return ibsic(board, usec_duration);
- }
- static int select_pci_ioctl(struct gpib_board_config *config, unsigned long arg)
- {
- struct gpib_select_pci_ioctl selection;
- int retval;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- retval = copy_from_user(&selection, (void __user *)arg, sizeof(selection));
- if (retval)
- return -EFAULT;
- config->pci_bus = selection.pci_bus;
- config->pci_slot = selection.pci_slot;
- return 0;
- }
- static int select_device_path_ioctl(struct gpib_board_config *config, unsigned long arg)
- {
- struct gpib_select_device_path_ioctl *selection;
- int retval;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- selection = vmalloc(sizeof(struct gpib_select_device_path_ioctl));
- if (!selection)
- return -ENOMEM;
- retval = copy_from_user(selection, (void __user *)arg,
- sizeof(struct gpib_select_device_path_ioctl));
- if (retval) {
- vfree(selection);
- return -EFAULT;
- }
- selection->device_path[sizeof(selection->device_path) - 1] = '\0';
- kfree(config->device_path);
- config->device_path = NULL;
- if (strlen(selection->device_path) > 0)
- config->device_path = kstrdup(selection->device_path, GFP_KERNEL);
- vfree(selection);
- return 0;
- }
- unsigned int num_gpib_events(const struct gpib_event_queue *queue)
- {
- return queue->num_events;
- }
- static int push_gpib_event_nolock(struct gpib_board *board, short event_type)
- {
- struct gpib_event_queue *queue = &board->event_queue;
- struct list_head *head = &queue->event_head;
- struct gpib_event *event;
- static const unsigned int max_num_events = 1024;
- int retval;
- if (num_gpib_events(queue) >= max_num_events) {
- short lost_event;
- queue->dropped_event = 1;
- retval = pop_gpib_event_nolock(board, queue, &lost_event);
- if (retval < 0)
- return retval;
- }
- event = kmalloc_obj(struct gpib_event, GFP_ATOMIC);
- if (!event) {
- queue->dropped_event = 1;
- dev_err(board->gpib_dev, "failed to allocate memory for event\n");
- return -ENOMEM;
- }
- INIT_LIST_HEAD(&event->list);
- event->event_type = event_type;
- list_add_tail(&event->list, head);
- queue->num_events++;
- dev_dbg(board->gpib_dev, "pushed event %i, %i in queue\n",
- (int)event_type, num_gpib_events(queue));
- return 0;
- }
- // push event onto back of event queue
- int push_gpib_event(struct gpib_board *board, short event_type)
- {
- unsigned long flags;
- int retval;
- spin_lock_irqsave(&board->event_queue.lock, flags);
- retval = push_gpib_event_nolock(board, event_type);
- spin_unlock_irqrestore(&board->event_queue.lock, flags);
- if (event_type == EVENT_DEV_TRG)
- board->status |= DTAS;
- if (event_type == EVENT_DEV_CLR)
- board->status |= DCAS;
- return retval;
- }
- EXPORT_SYMBOL(push_gpib_event);
- static int pop_gpib_event_nolock(struct gpib_board *board,
- struct gpib_event_queue *queue, short *event_type)
- {
- struct list_head *head = &queue->event_head;
- struct list_head *front = head->next;
- struct gpib_event *event;
- if (num_gpib_events(queue) == 0) {
- *event_type = EVENT_NONE;
- return 0;
- }
- if (front == head)
- return -EIO;
- if (queue->dropped_event) {
- queue->dropped_event = 0;
- return -EPIPE;
- }
- event = list_entry(front, struct gpib_event, list);
- *event_type = event->event_type;
- list_del(front);
- kfree(event);
- queue->num_events--;
- dev_dbg(board->gpib_dev, "popped event %i, %i in queue\n",
- (int)*event_type, num_gpib_events(queue));
- return 0;
- }
- // pop event from front of event queue
- int pop_gpib_event(struct gpib_board *board, struct gpib_event_queue *queue, short *event_type)
- {
- unsigned long flags;
- int retval;
- spin_lock_irqsave(&queue->lock, flags);
- retval = pop_gpib_event_nolock(board, queue, event_type);
- spin_unlock_irqrestore(&queue->lock, flags);
- return retval;
- }
- static int event_ioctl(struct gpib_board *board, unsigned long arg)
- {
- short user_event;
- int retval;
- short event;
- retval = pop_gpib_event(board, &board->event_queue, &event);
- if (retval < 0)
- return retval;
- user_event = event;
- retval = copy_to_user((void __user *)arg, &user_event, sizeof(user_event));
- if (retval)
- return -EFAULT;
- return 0;
- }
- static int request_system_control_ioctl(struct gpib_board *board, unsigned long arg)
- {
- int request_control;
- int retval;
- retval = copy_from_user(&request_control, (void __user *)arg, sizeof(request_control));
- if (retval)
- return -EFAULT;
- return ibrsc(board, request_control);
- }
- static int t1_delay_ioctl(struct gpib_board *board, unsigned long arg)
- {
- unsigned int cmd;
- unsigned int delay;
- int retval;
- if (!board->interface->t1_delay)
- return -ENOENT;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
- if (retval)
- return -EFAULT;
- delay = cmd;
- retval = board->interface->t1_delay(board, delay);
- if (retval < 0)
- return retval;
- board->t1_nano_sec = retval;
- return 0;
- }
- static const struct file_operations ib_fops = {
- .owner = THIS_MODULE,
- .llseek = NULL,
- .unlocked_ioctl = &ibioctl,
- .compat_ioctl = &ibioctl,
- .open = &ibopen,
- .release = &ibclose,
- };
- struct gpib_board board_array[GPIB_MAX_NUM_BOARDS];
- LIST_HEAD(registered_drivers);
- void init_gpib_descriptor(struct gpib_descriptor *desc)
- {
- desc->pad = 0;
- desc->sad = -1;
- desc->is_board = 0;
- desc->autopoll_enabled = 0;
- atomic_set(&desc->io_in_progress, 0);
- atomic_set(&desc->descriptor_busy, 0);
- }
- int gpib_register_driver(struct gpib_interface *interface, struct module *provider_module)
- {
- struct gpib_interface_list *entry;
- entry = kmalloc_obj(*entry);
- if (!entry)
- return -ENOMEM;
- entry->interface = interface;
- entry->module = provider_module;
- list_add(&entry->list, ®istered_drivers);
- return 0;
- }
- EXPORT_SYMBOL(gpib_register_driver);
- void gpib_unregister_driver(struct gpib_interface *interface)
- {
- int i;
- struct list_head *list_ptr;
- for (i = 0; i < GPIB_MAX_NUM_BOARDS; i++) {
- struct gpib_board *board = &board_array[i];
- if (board->interface == interface) {
- if (board->use_count > 0)
- pr_warn("gpib: Warning: deregistered interface %s in use\n",
- interface->name);
- iboffline(board);
- board->interface = NULL;
- }
- }
- for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers;) {
- struct gpib_interface_list *entry;
- entry = list_entry(list_ptr, struct gpib_interface_list, list);
- list_ptr = list_ptr->next;
- if (entry->interface == interface) {
- list_del(&entry->list);
- kfree(entry);
- }
- }
- }
- EXPORT_SYMBOL(gpib_unregister_driver);
- static void init_gpib_board_config(struct gpib_board_config *config)
- {
- memset(config, 0, sizeof(struct gpib_board_config));
- config->pci_bus = -1;
- config->pci_slot = -1;
- }
- void init_gpib_board(struct gpib_board *board)
- {
- board->interface = NULL;
- board->provider_module = NULL;
- board->buffer = NULL;
- board->buffer_length = 0;
- board->status = 0;
- init_waitqueue_head(&board->wait);
- mutex_init(&board->user_mutex);
- mutex_init(&board->big_gpib_mutex);
- board->locking_pid = 0;
- spin_lock_init(&board->locking_pid_spinlock);
- spin_lock_init(&board->spinlock);
- timer_setup(&board->timer, NULL, 0);
- board->dev = NULL;
- board->gpib_dev = NULL;
- init_gpib_board_config(&board->config);
- board->private_data = NULL;
- board->use_count = 0;
- INIT_LIST_HEAD(&board->device_list);
- board->pad = 0;
- board->sad = -1;
- board->usec_timeout = 3000000;
- board->parallel_poll_configuration = 0;
- board->online = 0;
- board->autospollers = 0;
- board->autospoll_task = NULL;
- init_event_queue(&board->event_queue);
- board->minor = -1;
- init_gpib_pseudo_irq(&board->pseudo_irq);
- board->master = 1;
- atomic_set(&board->stuck_srq, 0);
- board->local_ppoll_mode = 0;
- }
- int gpib_allocate_board(struct gpib_board *board)
- {
- if (!board->buffer) {
- board->buffer_length = 0x4000;
- board->buffer = vmalloc(board->buffer_length);
- if (!board->buffer) {
- board->buffer_length = 0;
- return -ENOMEM;
- }
- }
- return 0;
- }
- void gpib_deallocate_board(struct gpib_board *board)
- {
- short dummy;
- if (board->buffer) {
- vfree(board->buffer);
- board->buffer = NULL;
- board->buffer_length = 0;
- }
- while (num_gpib_events(&board->event_queue))
- pop_gpib_event(board, &board->event_queue, &dummy);
- }
- static void init_board_array(struct gpib_board *board_array, unsigned int length)
- {
- int i;
- for (i = 0; i < length; i++) {
- init_gpib_board(&board_array[i]);
- board_array[i].minor = i;
- }
- }
- void init_gpib_status_queue(struct gpib_status_queue *device)
- {
- INIT_LIST_HEAD(&device->list);
- INIT_LIST_HEAD(&device->status_bytes);
- device->num_status_bytes = 0;
- device->reference_count = 0;
- device->dropped_byte = 0;
- }
- static struct class *gpib_class;
- static int __init gpib_common_init_module(void)
- {
- int i;
- pr_info("GPIB core driver\n");
- init_board_array(board_array, GPIB_MAX_NUM_BOARDS);
- if (register_chrdev(GPIB_CODE, "gpib", &ib_fops)) {
- pr_err("gpib: can't get major %d\n", GPIB_CODE);
- return -EIO;
- }
- gpib_class = class_create("gpib_common");
- if (IS_ERR(gpib_class)) {
- pr_err("gpib: failed to create gpib class\n");
- unregister_chrdev(GPIB_CODE, "gpib");
- return PTR_ERR(gpib_class);
- }
- for (i = 0; i < GPIB_MAX_NUM_BOARDS; ++i)
- board_array[i].gpib_dev = device_create(gpib_class, NULL,
- MKDEV(GPIB_CODE, i), NULL, "gpib%i", i);
- return 0;
- }
- static void __exit gpib_common_exit_module(void)
- {
- int i;
- for (i = 0; i < GPIB_MAX_NUM_BOARDS; ++i)
- device_destroy(gpib_class, MKDEV(GPIB_CODE, i));
- class_destroy(gpib_class);
- unregister_chrdev(GPIB_CODE, "gpib");
- }
- int gpib_match_device_path(struct device *dev, const char *device_path_in)
- {
- if (device_path_in) {
- char *device_path;
- device_path = kobject_get_path(&dev->kobj, GFP_KERNEL);
- if (!device_path) {
- dev_err(dev, "kobject_get_path returned NULL.");
- return 0;
- }
- if (strcmp(device_path_in, device_path) != 0) {
- kfree(device_path);
- return 0;
- }
- kfree(device_path);
- }
- return 1;
- }
- EXPORT_SYMBOL(gpib_match_device_path);
- struct pci_dev *gpib_pci_get_device(const struct gpib_board_config *config, unsigned int vendor_id,
- unsigned int device_id, struct pci_dev *from)
- {
- struct pci_dev *pci_device = from;
- while ((pci_device = pci_get_device(vendor_id, device_id, pci_device))) {
- if (config->pci_bus >= 0 && config->pci_bus != pci_device->bus->number)
- continue;
- if (config->pci_slot >= 0 && config->pci_slot !=
- PCI_SLOT(pci_device->devfn))
- continue;
- if (gpib_match_device_path(&pci_device->dev, config->device_path) == 0)
- continue;
- return pci_device;
- }
- return NULL;
- }
- EXPORT_SYMBOL(gpib_pci_get_device);
- struct pci_dev *gpib_pci_get_subsys(const struct gpib_board_config *config, unsigned int vendor_id,
- unsigned int device_id, unsigned int ss_vendor,
- unsigned int ss_device,
- struct pci_dev *from)
- {
- struct pci_dev *pci_device = from;
- while ((pci_device = pci_get_subsys(vendor_id, device_id,
- ss_vendor, ss_device, pci_device))) {
- if (config->pci_bus >= 0 && config->pci_bus != pci_device->bus->number)
- continue;
- if (config->pci_slot >= 0 && config->pci_slot !=
- PCI_SLOT(pci_device->devfn))
- continue;
- if (gpib_match_device_path(&pci_device->dev, config->device_path) == 0)
- continue;
- return pci_device;
- }
- return NULL;
- }
- EXPORT_SYMBOL(gpib_pci_get_subsys);
- module_init(gpib_common_init_module);
- module_exit(gpib_common_exit_module);
|