Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3393 lines
94 KiB

  1. /*----------------------------------------------------------------------
  2. initc.c - init, common code(pull out of custom init.c, put in here)
  3. 1-27-99 - take out "\device\" in hardware\serialcomm reg entries, kpb.
  4. 1-20-99 - adjust unique_id in CreatePortDevice to start names at "RocketPort0".
  5. 1-25-99 - adjust again from "\Device\RocketPort0" to "RocketPort0". kpb.
  6. |----------------------------------------------------------------------*/
  7. #include "precomp.h"
  8. //------------ local variables -----------------------------------
  9. static int CheckPortName(IN OUT char *name,
  10. IN PSERIAL_DEVICE_EXTENSION extension);
  11. static int IsPortNameInHardwareMap(char *name);
  12. static char *szDosDevices = {"\\DosDevices\\"};
  13. static char *szDevice = {"\\Device\\"};
  14. #ifdef S_RK
  15. static char *szRocket = {"rocket"};
  16. static char *szRocketSys = {"rocketsys"};
  17. #else
  18. char *szRocket = {"vslinka"};
  19. char *szRocketSys = {"vslinkasys"};
  20. #endif
  21. typedef struct
  22. {
  23. char *response[2];
  24. int response_length[2];
  25. int nextstate[2];
  26. } MSTATE_CHOICE;
  27. static USHORT ErrNum = 1; // used with event logging
  28. #define SEND_CMD_STRING(portex,string) \
  29. ModemWrite(portex,(char *)string,sizeof(string) - 1)
  30. #define SEND_CMD_DELAY_STRING(portex,string) \
  31. ModemWriteDelay(portex,(char *)string,sizeof(string) - 1)
  32. #define READ_RESPONSE_STRINGS(portex,s0,s1,retries) \
  33. ModemReadChoice(portex,(char *)s0,sizeof(s0) - 1,(char *)s1,sizeof(s1) - 1,retries)
  34. #define READ_RESPONSE_STRING(portex,string,retries) \
  35. ModemRead(portex,(char *)string,sizeof(string) - 1,retries)
  36. #define ONE_SECOND 10
  37. #define TWO_SECONDS (2 * ONE_SECOND)
  38. #define THREE_SECONDS (3 * ONE_SECOND)
  39. #define FOUR_SECONDS (4 * ONE_SECOND)
  40. #define FIVE_SECONDS (5 * ONE_SECOND)
  41. #define TENTH_SECOND (ONE_SECOND / 10)
  42. #define HALF_SECOND (ONE_SECOND / 2)
  43. #define MAX_MODEM_ATTEMPTS 3
  44. #ifdef S_RK
  45. #define MAX_STALL 50 // fifo stall count
  46. #define RMODEM_FAILED 0
  47. #define RMODEM_NOT_LOADED 1
  48. #define RMODEM_LOADED 2
  49. #define VERSION_CHAR 'V'
  50. char ChecksumString[16];
  51. int gModemToggle = 0;
  52. typedef struct {
  53. int status;
  54. unsigned long index;
  55. PSERIAL_DEVICE_EXTENSION portex;
  56. } MODEM_STATE;
  57. //------------ local variables -----------------------------------
  58. void ModemTxFIFOWait(PSERIAL_DEVICE_EXTENSION ext);
  59. void ModemResetAll(PSERIAL_DEVICE_EXTENSION ext);
  60. void ChecksumAscii(unsigned short *valueptr);
  61. int IssueEvent(PSERIAL_DEVICE_EXTENSION ext,int (*modemfunc)(),MODEM_STATE *pModemState);
  62. void DownModem(MODEM_STATE *pModemState);
  63. #endif
  64. /*----------------------------------------------------------------------
  65. SerialUnload -
  66. This routine cleans up all of the memory associated with
  67. any of the devices belonging to the driver. It will
  68. loop through the device list.
  69. Arguments:
  70. DriverObject - Pointer to the driver object controling all of the
  71. devices.
  72. Return Value:
  73. None.
  74. |----------------------------------------------------------------------*/
  75. VOID SerialUnload (IN PDRIVER_OBJECT DriverObject)
  76. {
  77. PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
  78. // char full_sysname[40];
  79. #ifdef S_VS
  80. int i;
  81. #endif //S_VS
  82. #ifdef S_RK
  83. if (Driver.InterruptObject != NULL)
  84. {
  85. CONTROLLER_T *CtlP; /* ptr to controller structure */
  86. // Disable interupts from RocketPort clear the EOI and
  87. CtlP = Driver.irq_ext->CtlP;
  88. if(CtlP->BusType == Isa)
  89. {
  90. MyKdPrint(D_Init,("Clear ISA IRQ\n"))
  91. sDisGlobalInt(CtlP);
  92. sControllerEOI(CtlP);
  93. }
  94. if(CtlP->BusType == PCIBus)
  95. {
  96. MyKdPrint(D_Init,("Clear PCI IRQ\n"))
  97. sDisGlobalIntPCI(CtlP);
  98. sPCIControllerEOI(CtlP);
  99. }
  100. IoDisconnectInterrupt(Driver.InterruptObject);
  101. Driver.InterruptObject = NULL;
  102. }
  103. #endif
  104. #ifdef S_VS
  105. if (Driver.threadHandle != NULL)
  106. {
  107. ZwClose(Driver.threadHandle);
  108. Driver.threadHandle = NULL; // tell thread to kill itself
  109. time_stall(15); // wait 1.5 second
  110. }
  111. #endif
  112. if (Driver.TimerCreated != 0)
  113. {
  114. KeCancelTimer(&Driver.PollTimer);
  115. Driver.TimerCreated = 0;
  116. }
  117. if (DriverObject->DeviceObject != NULL)
  118. {
  119. // delete all the Deviceobjects and symbolic links
  120. RcktDeleteDevices(DriverObject);
  121. DriverObject->DeviceObject = NULL;
  122. }
  123. #ifdef S_VS
  124. if (Driver.MicroCodeImage != NULL)
  125. {
  126. our_free(Driver.MicroCodeImage, "MCI");
  127. Driver.MicroCodeImage = NULL;
  128. }
  129. if (Driver.nics != NULL)
  130. {
  131. for (i=0; i<VS1000_MAX_NICS; i++)
  132. {
  133. if (Driver.nics[i].NICHandle != NULL) {
  134. NicClose(&Driver.nics[i]);
  135. }
  136. }
  137. our_free(Driver.nics, "nics");
  138. }
  139. Driver.nics = NULL;
  140. if (Driver.NdisProtocolHandle != NULL)
  141. NicProtocolClose();
  142. Driver.NdisProtocolHandle = NULL;
  143. if (Driver.BindNames != NULL)
  144. ExFreePool(Driver.BindNames);
  145. Driver.BindNames = NULL;
  146. #endif
  147. if (Driver.DebugQ.QBase)
  148. {
  149. ExFreePool(Driver.DebugQ.QBase);
  150. Driver.DebugQ.QBase = NULL;
  151. }
  152. if (Driver.RegPath.Buffer != NULL)
  153. {
  154. ExFreePool(Driver.RegPath.Buffer);
  155. Driver.RegPath.Buffer = NULL;
  156. }
  157. if (Driver.OptionRegPath.Buffer != NULL)
  158. {
  159. ExFreePool(Driver.OptionRegPath.Buffer);
  160. Driver.OptionRegPath.Buffer = NULL;
  161. }
  162. }
  163. /*----------------------------------------------------------------------
  164. CreateDriverDevice - Create "rocket" driver object, this is for access to the
  165. driver as a whole. The monitoring program uses this to open up
  166. a channel to get driver information.
  167. Creates a symbolic link name to do special IOctl calls
  168. |----------------------------------------------------------------------*/
  169. NTSTATUS CreateDriverDevice(IN PDRIVER_OBJECT DriverObject,
  170. OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension)
  171. {
  172. PDEVICE_OBJECT deviceObject = NULL;
  173. NTSTATUS ntStatus;
  174. PSERIAL_DEVICE_EXTENSION extension = NULL;
  175. char full_ntname[40];
  176. char full_symname[40];
  177. MyKdPrint(D_Init,("CreateDriverDevice\n"))
  178. // Create an device object
  179. {
  180. strcpy(full_ntname,szDevice); // "\\Device\\"
  181. strcat(full_ntname,szRocketSys); // "RocketSys"
  182. // special name
  183. strcpy(full_symname,szDosDevices); // "\\DosDevices\\"
  184. strcat(full_symname,szRocket); // "ROCKET" or "VSLINKA"
  185. ntStatus = IoCreateDevice(
  186. DriverObject,
  187. sizeof(SERIAL_DEVICE_EXTENSION),
  188. CToU1(full_ntname),
  189. //#ifdef NT50
  190. // FILE_DEVICE_BUS_EXTENDER,
  191. //#else
  192. 0, // unknown device? , so make a 0 device(unknown?)
  193. //#endif
  194. 0, // file characteristics
  195. FALSE, // exclusive?
  196. &deviceObject); // create this
  197. if (!NT_SUCCESS(ntStatus))
  198. {
  199. MyKdPrint(D_Init,("Err CDD1A\n"))
  200. switch (ntStatus)
  201. {
  202. case STATUS_INSUFFICIENT_RESOURCES:
  203. MyKdPrint(D_Init,("Err CDD1B\n"))
  204. break;
  205. case STATUS_OBJECT_NAME_EXISTS:
  206. MyKdPrint(D_Init,("Err CDD1C\n"))
  207. break;
  208. case STATUS_OBJECT_NAME_COLLISION:
  209. MyKdPrint(D_Init,("Err CDD1D\n"))
  210. break;
  211. default:
  212. MyKdPrint(D_Init,("Err CDD1E\n"))
  213. break;
  214. }
  215. return(ntStatus);
  216. }
  217. MyKdPrint(D_Init,("CreateDriver DevObj[%x]: NT:%s\n",
  218. deviceObject, szRocketSys))
  219. //
  220. // Create a symbolic link, e.g. a name that a Win32 app can specify
  221. // to open the device
  222. //
  223. // initialize some of the extension values to make it look like
  224. // another serial port to fake out the supporting functions
  225. // ie open,close, ...
  226. deviceObject->Flags |= DO_BUFFERED_IO;
  227. #ifdef NT50
  228. //
  229. // Enables Irp assignments to be accepted
  230. //
  231. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  232. #endif
  233. extension = deviceObject->DeviceExtension;
  234. // Initialize the list heads for the read, write, and mask queues.
  235. // These lists will hold all of the queued IRP's for the device.
  236. InitializeListHead(&extension->ReadQueue);
  237. InitializeListHead(&extension->WriteQueue);
  238. InitializeListHead(&extension->PurgeQueue);
  239. KeInitializeEvent(&extension->PendingIRPEvent, SynchronizationEvent,
  240. FALSE);
  241. // init to 1, so on irp enter its 1 to 2, on exit 2 to 1. 0 on pnp stop.
  242. extension->PendingIRPCnt = 1;
  243. // Mark this device as not being opened by anyone. We keep a
  244. // variable around so that spurious interrupts are easily
  245. // dismissed by the ISR.
  246. extension->DeviceIsOpen = FALSE;
  247. extension->WriteLength = 0;
  248. extension->DeviceObject = deviceObject;
  249. strcpy(extension->NtNameForPort, szRocketSys); // "RocketSys"
  250. extension->DeviceType = DEV_BOARD; // really a driver type, but..
  251. extension->UniqueId = 0;
  252. #ifdef NT50
  253. extension->PowerState = PowerDeviceD0;
  254. #endif
  255. //------ add to the global links
  256. Driver.driver_ext = extension;
  257. // make the public ROCKET or VSLINKA name for applications
  258. ntStatus = IoCreateSymbolicLink(CToU1(full_symname),
  259. CToU2(full_ntname));
  260. if (!NT_SUCCESS(ntStatus))
  261. {
  262. // Symbolic link creation failed- note this & then delete th
  263. MyKdPrint(D_Init,("CDD1E\n"))
  264. return(ntStatus);
  265. }
  266. extension->CreatedSymbolicLink = TRUE;
  267. strcpy(extension->SymbolicLinkName, szRocket); // "ROCKET"
  268. //Driver.RocketSysDeviceObject = deviceObject; //set global device object
  269. //extension->config = ExAllocatePool(NonPagedPool, sizeof(DEVICE_CONFIG));
  270. //RtlZeroMemory(extension->config, sizeof(DEVICE_CONFIG));
  271. #ifdef S_RK
  272. //extension->CtlP = ExAllocatePool(NonPagedPool, sizeof(CONTROLLER_T));
  273. //RtlZeroMemory(extension->config, sizeof(CONTROLLER_T));
  274. #endif
  275. //------- Pass back the extension to the caller.
  276. if (DeviceExtension != NULL)
  277. *DeviceExtension = extension;
  278. }
  279. return(ntStatus);
  280. }
  281. /*----------------------------------------------------------------------
  282. CreateBoardDevice - Create "rocket" driver object, this is for access to the
  283. driver as a whole. The monitoring program uses this to open up
  284. a channel to get driver information.
  285. Creates a symbolic link name to do special IOctl calls
  286. Need one for each board so we can use them to do IOReportResources
  287. per board(needed for diferent buses.)
  288. The first board device gets a "ROCKET" symbolic link so we can
  289. open it and query the driver as a whole.
  290. |----------------------------------------------------------------------*/
  291. NTSTATUS CreateBoardDevice(IN PDRIVER_OBJECT DriverObject,
  292. OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension)
  293. {
  294. PDEVICE_OBJECT deviceObject = NULL;
  295. NTSTATUS ntStatus;
  296. PSERIAL_DEVICE_EXTENSION extension = NULL;
  297. char full_ntname[40];
  298. char full_symname[40];
  299. char ntname[40];
  300. // for naming device objects, resource submitting, etc we need a
  301. // unique name or id which is unique to the driver. We used to
  302. // use board number or port number for this, but with pnp, things
  303. // come and go on the fly, so instead we create a unique number
  304. // each time we create one of these things.
  305. static int unique_id = 0;
  306. MyKdPrint(D_Init,("CreateBoardDevice\n"))
  307. // Create an EXCLUSIVE device object (only 1 thread at a time
  308. // can make requests to this device)
  309. {
  310. strcpy(ntname, szRocketSys);
  311. our_ultoa(unique_id, &ntname[strlen(ntname)], 10);
  312. strcpy(full_ntname,szDevice); // "\\Device\\"
  313. strcat(full_ntname,ntname); // "RocketPort#"
  314. full_symname[0] = 0;
  315. ntStatus = IoCreateDevice(
  316. DriverObject,
  317. sizeof(SERIAL_DEVICE_EXTENSION),
  318. CToU1(full_ntname),
  319. #ifdef NT50
  320. FILE_DEVICE_BUS_EXTENDER,
  321. #else
  322. 0, // unknown device? , so make a 0 device(unknown?)
  323. #endif
  324. 0, // file characteristics
  325. FALSE, // exclusive?
  326. &deviceObject); // create this
  327. if (!NT_SUCCESS(ntStatus))
  328. {
  329. MyKdPrint(D_Error,("CBD1A\n"))
  330. switch (ntStatus)
  331. {
  332. case STATUS_INSUFFICIENT_RESOURCES:
  333. MyKdPrint(D_Error,("CBD1B\n"))
  334. break;
  335. case STATUS_OBJECT_NAME_EXISTS:
  336. MyKdPrint(D_Error,("CBD1C\n"))
  337. break;
  338. case STATUS_OBJECT_NAME_COLLISION:
  339. MyKdPrint(D_Error,("CBD1D\n"))
  340. break;
  341. default:
  342. MyKdPrint(D_Error,("CBD1E\n"))
  343. break;
  344. }
  345. return(ntStatus);
  346. }
  347. ++unique_id; // go to next id so next call will be different.
  348. // Create a symbolic link, e.g. a name that a Win32 app can specify
  349. // to open the device
  350. //
  351. // initialize some of the extension values to make it look like
  352. // another serial port to fake out the supporting functions
  353. // ie open,close, ...
  354. deviceObject->Flags |= DO_BUFFERED_IO;
  355. #ifdef NT50
  356. //
  357. // Enables Irp assignments to be accepted
  358. //
  359. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  360. #endif
  361. MyKdPrint(D_Init,("CreateBoard DevObj[%x]: NT:%s\n",
  362. deviceObject, ntname))
  363. extension = deviceObject->DeviceExtension;
  364. // Initialize the list heads for the read, write, and mask queues.
  365. // These lists will hold all of the queued IRP's for the device.
  366. InitializeListHead(&extension->ReadQueue);
  367. InitializeListHead(&extension->WriteQueue);
  368. //InitializeListHead(&extension->MaskQueue);
  369. InitializeListHead(&extension->PurgeQueue);
  370. KeInitializeEvent(&extension->PendingIRPEvent, SynchronizationEvent,
  371. FALSE);
  372. // init to 1, so on irp enter its 1 to 2, on exit 2 to 1. 0 on pnp stop.
  373. extension->PendingIRPCnt = 1;
  374. // Mark this device as not being opened by anyone. We keep a
  375. // variable around so that spurious interrupts are easily
  376. // dismissed by the ISR.
  377. extension->DeviceIsOpen = FALSE;
  378. extension->WriteLength = 0;
  379. extension->DeviceObject = deviceObject;
  380. strcpy(extension->NtNameForPort, ntname); // "RocketSys"
  381. extension->DeviceType = DEV_BOARD;
  382. extension->UniqueId = unique_id;
  383. #ifdef NT50
  384. extension->PowerState = PowerDeviceD0;
  385. #endif
  386. //------ add to the chain of boards
  387. if (Driver.board_ext == NULL)
  388. Driver.board_ext = extension;
  389. else
  390. {
  391. PSERIAL_DEVICE_EXTENSION add_ext;
  392. add_ext = Driver.board_ext;
  393. while (add_ext->board_ext != NULL)
  394. add_ext = add_ext->board_ext;
  395. add_ext->board_ext = extension;
  396. }
  397. extension->SymbolicLinkName[0] = 0;
  398. extension->config = ExAllocatePool(NonPagedPool, sizeof(DEVICE_CONFIG));
  399. if ( extension->config == NULL ) {
  400. return STATUS_INSUFFICIENT_RESOURCES;
  401. }
  402. RtlZeroMemory(extension->config, sizeof(DEVICE_CONFIG));
  403. #ifdef S_RK
  404. extension->CtlP = ExAllocatePool(NonPagedPool, sizeof(CONTROLLER_T));
  405. if ( extension->CtlP == NULL ) {
  406. return STATUS_INSUFFICIENT_RESOURCES;
  407. }
  408. RtlZeroMemory(extension->config, sizeof(CONTROLLER_T));
  409. #endif
  410. #ifdef S_VS
  411. // allocate the hdlc & port manager structs
  412. extension->hd = (Hdlc *)our_locked_alloc(sizeof(Hdlc), "Dhd");
  413. extension->pm = (PortMan *)our_locked_alloc(sizeof(PortMan),"Dpm");
  414. extension->pm->hd = extension->hd; // set this up, avoids trouble
  415. #endif
  416. //------- Pass back the extension to the caller.
  417. if (DeviceExtension != NULL)
  418. *DeviceExtension = extension;
  419. }
  420. return(ntStatus);
  421. }
  422. /*----------------------------------------------------------------------
  423. CreateReconfigPortDevices -
  424. This routine attempts to resize a rocketport or vs1000 number of
  425. ports.
  426. |----------------------------------------------------------------------*/
  427. NTSTATUS CreateReconfigPortDevices(IN PSERIAL_DEVICE_EXTENSION board_ext,
  428. int new_num_ports)
  429. {
  430. PSERIAL_DEVICE_EXTENSION newExtension = NULL;
  431. PSERIAL_DEVICE_EXTENSION next_ext;
  432. PSERIAL_DEVICE_EXTENSION port_ext;
  433. int ch;
  434. NTSTATUS stat;
  435. // bugbug: if pnp-ports, we should be adding and removing pdo's,
  436. // not fdo's.
  437. int is_fdo = 1;
  438. int existing_ports;
  439. MyKdPrint(D_Init,("ReconfigNumPorts"))
  440. if (board_ext == NULL)
  441. {
  442. return STATUS_INSUFFICIENT_RESOURCES;
  443. }
  444. #ifdef S_RK
  445. // doesn't make as much sense to redo this on the fly as in VS.
  446. // rocketport special re-configure startup code would be needed.
  447. return STATUS_INSUFFICIENT_RESOURCES;
  448. #endif
  449. // code needs work! don't allow for nt40 as well....
  450. return STATUS_INSUFFICIENT_RESOURCES;
  451. #ifdef NT50
  452. // if we are doing pnp-ports, we probably need to remove the
  453. // pdo's then inform the os to rescan pdos.
  454. if (!Driver.NoPnpPorts)
  455. return STATUS_INSUFFICIENT_RESOURCES;
  456. #endif
  457. existing_ports = NumPorts(board_ext);
  458. if (new_num_ports == existing_ports)
  459. return STATUS_SUCCESS;
  460. if (new_num_ports == 0)
  461. return STATUS_INSUFFICIENT_RESOURCES;
  462. MyKdPrint(D_Init,("ReconfigNumPorts B"))
  463. ++Driver.Stop_Poll; // flag to stop poll access
  464. if (new_num_ports < existing_ports) // want less ports
  465. {
  466. // see if anyones got the ports we want to kill off open.
  467. port_ext = board_ext->port_ext;
  468. for (ch=0; ch<existing_ports; ch++)
  469. {
  470. if (ch>=new_num_ports)
  471. {
  472. if (port_ext->DeviceIsOpen)
  473. {
  474. --Driver.Stop_Poll; // flag to stop poll access
  475. MyKdPrint(D_Error,("Port OpenErr\n"))
  476. return STATUS_INSUFFICIENT_RESOURCES; // no they are open
  477. }
  478. }
  479. port_ext = port_ext->port_ext;
  480. }
  481. MyKdPrint(D_Error,("Removing Ports\n"))
  482. //---- must be ok to kill them off
  483. port_ext = board_ext->port_ext;
  484. for (ch=0; ch<existing_ports; ch++)
  485. {
  486. next_ext = port_ext->port_ext;
  487. if (ch>=new_num_ports)
  488. {
  489. RcktDeletePort(port_ext);
  490. }
  491. port_ext = next_ext;
  492. }
  493. }
  494. else if (new_num_ports > existing_ports) // want more ports
  495. {
  496. for (ch=existing_ports; ch<new_num_ports; ch++)
  497. {
  498. stat = CreatePortDevice(Driver.GlobalDriverObject,
  499. board_ext,
  500. &newExtension,
  501. ch,is_fdo);
  502. if (stat != STATUS_SUCCESS)
  503. {
  504. --Driver.Stop_Poll; // flag to stop poll access
  505. MyKdPrint(D_Error,("StartErr 8E"))
  506. return stat;
  507. }
  508. } // loop thru ports
  509. } // if more ports
  510. board_ext->config->NumPorts = new_num_ports;
  511. #ifdef S_VS
  512. stat = VSSpecialStartup(board_ext);
  513. if (stat != STATUS_SUCCESS)
  514. {
  515. --Driver.Stop_Poll; // flag to start poll access
  516. MyKdPrint(D_Error,("StartErr 8F"))
  517. return stat;
  518. }
  519. #endif
  520. --Driver.Stop_Poll; // flag to stop poll access
  521. return STATUS_SUCCESS;
  522. }
  523. /*----------------------------------------------------------------------
  524. CreatePortDevices -
  525. This routine attempts to initialize all the ports on a multiport board
  526. Arguments:
  527. DriverObject - Simply passed on to the controller initialization routine.
  528. ConfigData - A linked list of configuration information for all
  529. the ports on a multiport card.
  530. DeviceExtension - Will point to the first successfully initialized
  531. port on the multiport card.
  532. Return Value: None.
  533. |----------------------------------------------------------------------*/
  534. NTSTATUS CreatePortDevices(IN PDRIVER_OBJECT DriverObject)
  535. {
  536. PSERIAL_DEVICE_EXTENSION newExtension = NULL;
  537. int ch, bd;
  538. NTSTATUS stat;
  539. int is_fdo = 1;
  540. PSERIAL_DEVICE_EXTENSION ext;
  541. ext = Driver.board_ext;
  542. bd = 0;
  543. while (ext)
  544. {
  545. for (ch=0; ch<ext->config->NumPorts; ch++)
  546. {
  547. stat = CreatePortDevice(DriverObject,
  548. ext,
  549. &newExtension,
  550. ch,is_fdo);
  551. if (stat != STATUS_SUCCESS)
  552. return stat;
  553. stat = StartPortHardware(newExtension, ch);
  554. if (stat != STATUS_SUCCESS)
  555. return stat;
  556. }
  557. ++bd;
  558. ext = ext->board_ext; // next in chain
  559. } // while ext
  560. return STATUS_SUCCESS;
  561. }
  562. /*----------------------------------------------------------------------
  563. StartPortHardware -
  564. |----------------------------------------------------------------------*/
  565. NTSTATUS StartPortHardware(IN PSERIAL_DEVICE_EXTENSION port_ext,
  566. int chan_num)
  567. {
  568. #ifdef S_VS
  569. int i;
  570. PSERIAL_DEVICE_EXTENSION board_ext;
  571. board_ext = port_ext->board_ext;
  572. MyKdPrint(D_Pnp, ("StartHrdw bd:%d ch:%d\n",
  573. BoardExtToNumber(board_ext), chan_num))
  574. if (port_ext->Port == NULL)
  575. {
  576. port_ext->Port = board_ext->pm->sp[chan_num];
  577. if (port_ext->Port == NULL)
  578. {
  579. MyKdPrint(D_Error,("FATAL Err4F\n"))
  580. KdBreakPoint();
  581. }
  582. }
  583. #else
  584. CONTROLLER_T *CtlP; /* ptr to controller structure */
  585. PSERIAL_DEVICE_EXTENSION board_ext;
  586. int aiop_i, ch_i;
  587. board_ext = port_ext->board_ext;
  588. //board_num = BoardExtToNumber(board_ext);
  589. MyKdPrint(D_Pnp,("StartHrdw bd:%d ch:%d\n",
  590. BoardExtToNumber(board_ext), chan_num))
  591. CtlP = board_ext->CtlP; // point to our board struct
  592. // Set pointers to the Rocket's info
  593. port_ext->ChP = &port_ext->ch;
  594. // bugbug: what about special rocketmodem startup? Should we
  595. // be doing this for pdo's and fdo's? Should we have a flag
  596. // indicating job done?
  597. aiop_i = chan_num / CtlP->PortsPerAiop;
  598. ch_i = chan_num % CtlP->PortsPerAiop;
  599. if(!sInitChan(CtlP, // ptr to controller struct
  600. port_ext->ChP, // ptr to chan struct
  601. aiop_i, // aiop #
  602. (unsigned char)ch_i)) // chan #
  603. {
  604. Eprintf("Err Ch %d on Brd %d", chan_num+1,
  605. BoardExtToNumber(board_ext)+1);
  606. return STATUS_INSUFFICIENT_RESOURCES;
  607. }
  608. #endif
  609. return STATUS_SUCCESS;
  610. }
  611. /*----------------------------------------------------------------------
  612. CreatePortDevice -
  613. Forms and sets up names, creates the device, initializes kernel
  614. synchronization structures, allocates the typeahead buffer,
  615. sets up defaults, etc.
  616. Arguments:
  617. DriverObject - Just used to create the device object.
  618. ParentExtension - a pnp port this will be null.
  619. DeviceExtension - Points to the device extension of the successfully
  620. initialized controller. We return this handle.
  621. chan_num - 0,1,2,... port index
  622. is_fdo - is a functional device object(normal port) as apposed to
  623. a pdo(physical device object) which is used to pnp enumerate
  624. "found" hardware by our driver.
  625. Return Value:
  626. STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
  627. otherwise.
  628. |----------------------------------------------------------------------*/
  629. NTSTATUS CreatePortDevice(
  630. IN PDRIVER_OBJECT DriverObject,
  631. IN PSERIAL_DEVICE_EXTENSION ParentExtension,
  632. OUT PSERIAL_DEVICE_EXTENSION *DeviceExtension,
  633. IN int chan_num, // 0,1,2,... port index
  634. IN int is_fdo) // is a functional device object(normal port)
  635. {
  636. char full_ntname[40];
  637. char comname[16];
  638. char ntname[20];
  639. NTSTATUS status = STATUS_SUCCESS;
  640. int stat;
  641. ULONG do_type;
  642. PUNICODE_STRING pucodename;
  643. static int unique_id = 0;
  644. ULONG do_characteristics;
  645. BOOLEAN do_is_exclusive;
  646. // Points to the device object (not the extension) created
  647. // for this device.
  648. PDEVICE_OBJECT deviceObject;
  649. // Points to the device extension for the device object
  650. // (see above) created for the device we are initializing.
  651. PSERIAL_DEVICE_EXTENSION extension = NULL;
  652. #ifdef S_VS
  653. strcpy(ntname, "Vslinka");
  654. #else
  655. strcpy(ntname, "RocketPort");
  656. #endif
  657. // copy over the name in the configuration for dos-name
  658. strcpy(comname, ParentExtension->config->port[chan_num].Name);
  659. // setup the nt io-object nt-name
  660. if (is_fdo)
  661. {
  662. strcpy(full_ntname, szDevice); // "\\Device\\"
  663. }
  664. else
  665. {
  666. // this is what serenum does for naming its pdo's
  667. strcpy(full_ntname, "\\Serial\\");
  668. strcat(ntname, "Pdo"); // just to make sure its unique
  669. }
  670. our_ultoa(unique_id, &ntname[strlen(ntname)], 10);
  671. strcat(full_ntname, ntname);
  672. if (is_fdo)
  673. {
  674. ++unique_id; // go to next id so next call will be different.
  675. // normal case(nt40), and a functional device object in nt5
  676. stat = CheckPortName(comname, NULL); // ensure name is unique
  677. if (stat) // name changed
  678. {
  679. // save back the new name to the configuration struct
  680. strcpy(ParentExtension->config->port[chan_num].Name, comname);
  681. }
  682. do_type = FILE_DEVICE_SERIAL_PORT;
  683. do_characteristics = 0;
  684. do_is_exclusive = TRUE;
  685. }
  686. else
  687. {
  688. // nt5 pnp physical device object(spawns a fdo later)
  689. //do_type = FILE_DEVICE_BUS_EXTENDER;
  690. do_type = FILE_DEVICE_UNKNOWN;
  691. #ifdef NT50
  692. // nt4 doesn't know what FILE_AUTOGENERATED_DEVICE_NAME is.
  693. do_characteristics = FILE_AUTOGENERATED_DEVICE_NAME;
  694. #else
  695. do_characteristics = 0;
  696. #endif
  697. do_is_exclusive = FALSE;
  698. //pucodename = NULL; // no name if a PDO
  699. }
  700. pucodename = CToU1(full_ntname);
  701. //---------------------------- Create the device object for this device.
  702. status = IoCreateDevice(
  703. DriverObject,
  704. sizeof(SERIAL_DEVICE_EXTENSION),
  705. pucodename, // name
  706. do_type, // FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SERIAL_PORT, etc
  707. do_characteristics,// characteristics
  708. do_is_exclusive, // exclusive
  709. &deviceObject); // new thing this call creates
  710. // If we couldn't create the device object, then there
  711. // is no point in going on.
  712. if (!NT_SUCCESS(status))
  713. {
  714. MyKdPrint(D_Init,("Err, IoCreate: NT:%s, SYM:%s\n",
  715. ntname, comname))
  716. EventLog(DriverObject,
  717. status,
  718. SERIAL_DEVICEOBJECT_FAILED,
  719. 0, NULL);
  720. return STATUS_INSUFFICIENT_RESOURCES;
  721. }
  722. // The device object has a pointer to an area of non-paged
  723. // pool allocated for this device. This will be the device extension.
  724. extension = deviceObject->DeviceExtension;
  725. // Zero all of the memory associated with the device extension.
  726. RtlZeroMemory(extension, sizeof(SERIAL_DEVICE_EXTENSION));
  727. extension->PortIndex = chan_num; // record the port index 0,1,2..
  728. // for NT5.0, set this up here so we don't crash.(NT4.0 sets
  729. // up prior to this.
  730. extension->port_config = &ParentExtension->config->port[chan_num];
  731. extension->UniqueId = unique_id;
  732. if (!is_fdo)
  733. {
  734. MyKdPrint(D_Init,("PDO-"))
  735. }
  736. MyKdPrint(D_Init,("CreatePort DevObj[%x]: NT:%s, SYM:%s\n",
  737. deviceObject, ntname, comname))
  738. // save off a ptr to our parent board extension
  739. extension->board_ext = ParentExtension;
  740. {
  741. PSERIAL_DEVICE_EXTENSION add_ext = NULL;
  742. if (is_fdo)
  743. {
  744. //------ add to the chain of ports under board ext
  745. if (ParentExtension->port_ext == NULL)
  746. ParentExtension->port_ext = extension;
  747. else
  748. add_ext = ParentExtension->port_ext;
  749. }
  750. else // pdo, ejected pnp enumeration
  751. {
  752. //------ add to the chain of pdo-ports under board ext
  753. if (ParentExtension->port_pdo_ext == NULL)
  754. ParentExtension->port_pdo_ext = extension;
  755. else
  756. add_ext = ParentExtension->port_pdo_ext;
  757. }
  758. if (add_ext)
  759. {
  760. while (add_ext->port_ext != NULL)
  761. add_ext = add_ext->port_ext;
  762. add_ext->port_ext = extension;
  763. }
  764. }
  765. // Initialize the list heads for the read, write, and mask queues.
  766. // These lists will hold all of the queued IRP's for the device.
  767. InitializeListHead(&extension->ReadQueue);
  768. InitializeListHead(&extension->WriteQueue);
  769. //InitializeListHead(&extension->MaskQueue);
  770. InitializeListHead(&extension->PurgeQueue);
  771. // Initialize the spinlock associated with fields read (& set)
  772. // by IO Control functions.
  773. KeInitializeSpinLock(&extension->ControlLock);
  774. // Initialize the timers used to timeout operations.
  775. KeInitializeTimer(&extension->ReadRequestTotalTimer);
  776. KeInitializeTimer(&extension->ReadRequestIntervalTimer);
  777. KeInitializeTimer(&extension->WriteRequestTotalTimer);
  778. KeInitializeTimer(&extension->XoffCountTimer);
  779. KeInitializeDpc(&extension->CompleteWriteDpc,
  780. SerialCompleteWrite,
  781. extension);
  782. KeInitializeDpc(&extension->CompleteReadDpc,
  783. SerialCompleteRead,
  784. extension);
  785. // Timeout Dpc initialization
  786. KeInitializeDpc(&extension->TotalReadTimeoutDpc,
  787. SerialReadTimeout,
  788. extension);
  789. KeInitializeDpc(&extension->IntervalReadTimeoutDpc,
  790. SerialIntervalReadTimeout,
  791. extension);
  792. KeInitializeDpc(&extension->TotalWriteTimeoutDpc,
  793. SerialWriteTimeout,
  794. extension);
  795. KeInitializeDpc(&extension->CommErrorDpc,
  796. SerialCommError,
  797. extension);
  798. KeInitializeDpc(&extension->CommWaitDpc,
  799. SerialCompleteWait,
  800. extension);
  801. KeInitializeDpc(&extension->XoffCountTimeoutDpc,
  802. SerialTimeoutXoff,
  803. extension);
  804. KeInitializeDpc(&extension->XoffCountCompleteDpc,
  805. SerialCompleteXoff,
  806. extension);
  807. // Get a "back pointer" to the device object and specify
  808. // that this driver only supports buffered IO. This basically
  809. // means that the IO system copies the users data to and from
  810. // system supplied buffers.
  811. extension->DeviceObject = deviceObject;
  812. extension->DevStatus = 0;
  813. deviceObject->Flags |= DO_BUFFERED_IO;
  814. #ifdef NT50
  815. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  816. if (!is_fdo) // its a PDO, so adjust stack requirements
  817. {
  818. deviceObject->StackSize += ParentExtension->DeviceObject->StackSize;
  819. }
  820. #endif
  821. KeInitializeEvent(&extension->PendingIRPEvent, SynchronizationEvent,
  822. FALSE);
  823. // init to 1, so on irp enter its 1 to 2, on exit 2 to 1. 0 on pnp stop.
  824. extension->PendingIRPCnt = 1;
  825. // Set up the default device control fields.
  826. // Note that if the values are changed after
  827. // the file is open, they do NOT revert back
  828. // to the old value at file close.
  829. extension->SpecialChars.XonChar = SERIAL_DEF_XON;
  830. extension->SpecialChars.XoffChar = SERIAL_DEF_XOFF;
  831. extension->SpecialChars.ErrorChar=0;
  832. extension->SpecialChars.EofChar=0;
  833. extension->SpecialChars.EventChar=0;
  834. extension->SpecialChars.BreakChar=0;
  835. extension->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
  836. extension->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
  837. extension->BaudRate = 9600;
  838. extension->LineCtl.Parity = NO_PARITY;
  839. extension->LineCtl.WordLength = 8;
  840. extension->LineCtl.StopBits = STOP_BIT_1;
  841. #ifdef S_RK
  842. extension->ModemCtl=COM_MDM_RTS | COM_MDM_DTR;
  843. extension->IntEnables =(RXINT_EN | MCINT_EN | CHANINT_EN | TXINT_EN);
  844. #endif
  845. // We set up the default xon/xoff limits.
  846. extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
  847. extension->HandFlow.XonLimit = extension->BufferSize >> 1;
  848. extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
  849. (extension->BufferSize>>4));
  850. // Initialize stats counters
  851. extension->OurStats.ReceivedCount = 0L;
  852. extension->OurStats.TransmittedCount = 0L;
  853. extension->OurStats.ParityErrorCount = 0L;
  854. extension->OurStats.FrameErrorCount = 0L;
  855. extension->OurStats.SerialOverrunErrorCount = 0L;
  856. extension->OurStats.BufferOverrunErrorCount = 0L;
  857. // Mark this device as not being opened by anyone. We keep a
  858. // variable around so that spurious interrupts are easily
  859. // dismissed by the ISR.
  860. extension->DeviceIsOpen = FALSE;
  861. extension->WriteLength = 0;
  862. #ifdef NT50
  863. extension->PowerState = PowerDeviceD0;
  864. #endif
  865. // This call will set up the naming necessary for
  866. // external applications to get to the driver. It
  867. // will also set up the device map.
  868. strcpy(extension->NtNameForPort, ntname); // RocketPort# or VSLINKA#
  869. strcpy(extension->SymbolicLinkName, comname); // "COM#"
  870. if (is_fdo)
  871. {
  872. SerialSetupExternalNaming(extension); // Configure ports!!!!
  873. // Check for default settings in registry
  874. InitPortsSettings(extension);
  875. }
  876. else
  877. {
  878. // eject PDOs (physical device objects)representing port hardware.
  879. extension->IsPDO = 1; // we are a pdo
  880. }
  881. // Store values into the extension for interval timing.
  882. // If the interval timer is less than a second then come
  883. // in with a short "polling" loop.
  884. // For large ( >2 seconds) use a 1 second poller.
  885. extension->ShortIntervalAmount.QuadPart = -1;
  886. extension->LongIntervalAmount.QuadPart = -10000000;
  887. extension->CutOverAmount.QuadPart = 200000000;
  888. //------- Pass back the extension to the caller.
  889. *DeviceExtension = extension;
  890. return STATUS_SUCCESS;
  891. }
  892. /*-----------------------------------------------------------------------
  893. RcktDeleteDriverObj - This routine will delete a board and all its ports
  894. for PnP remove handling.
  895. |----------------------------------------------------------------------*/
  896. VOID RcktDeleteDriverObj(IN PSERIAL_DEVICE_EXTENSION extension)
  897. {
  898. //int i;
  899. //PSERIAL_DEVICE_EXTENSION ext;
  900. PSERIAL_DEVICE_EXTENSION del_ext;
  901. MyKdPrint(D_Init,("Delete Driver Obj:%x\n", extension->DeviceObject))
  902. MyKdPrint(D_Init,(" IrpCnt:%x\n", extension->PendingIRPCnt))
  903. if (NULL == extension)
  904. {
  905. MyKdPrint(D_Init,("Err8U\n"))
  906. return;
  907. }
  908. ++Driver.Stop_Poll; // flag to stop poll access
  909. del_ext = extension; // now kill board
  910. SerialCleanupDevice(del_ext); // delete any port stuff on ext.
  911. #ifdef NT50
  912. if (del_ext->LowerDeviceObject != NULL)
  913. {
  914. IoDetachDevice(del_ext->LowerDeviceObject);
  915. del_ext->LowerDeviceObject = NULL;
  916. }
  917. #endif
  918. IoDeleteDevice(del_ext->DeviceObject);
  919. --Driver.Stop_Poll; // flag to stop poll access
  920. }
  921. /*----------------------------------------------------------------------
  922. RcktDeleteDevices - This routine will delete all devices
  923. |----------------------------------------------------------------------*/
  924. VOID RcktDeleteDevices(IN PDRIVER_OBJECT DriverObject)
  925. {
  926. PDEVICE_OBJECT currentDevice = DriverObject->DeviceObject;
  927. int i;
  928. i = 0;
  929. while(currentDevice)
  930. {
  931. PSERIAL_DEVICE_EXTENSION extension = currentDevice->DeviceExtension;
  932. currentDevice = currentDevice->NextDevice;
  933. SerialCleanupDevice(extension);
  934. #ifdef NT50
  935. if (extension->LowerDeviceObject != NULL)
  936. {
  937. IoDetachDevice(extension->LowerDeviceObject);
  938. extension->LowerDeviceObject = NULL;
  939. }
  940. #endif
  941. MyKdPrint(D_Init,("RcktDeleteDev Obj:%x\n", extension->DeviceObject))
  942. //MyKdPrint(D_Init,(" IrpCnt:%x\n", extension->PendingIRPCnt))
  943. IoDeleteDevice(extension->DeviceObject);
  944. i++;
  945. }
  946. MyKdPrint(D_Init,("Deleted %d Device Objects\n", i))
  947. }
  948. /*----------------------------------------------------------------------
  949. RcktDeleteBoard - This routine will delete a board and all its ports
  950. for PnP remove handling.
  951. |----------------------------------------------------------------------*/
  952. VOID RcktDeleteBoard(IN PSERIAL_DEVICE_EXTENSION extension)
  953. {
  954. int i;
  955. PSERIAL_DEVICE_EXTENSION ext;
  956. PSERIAL_DEVICE_EXTENSION del_ext;
  957. MyKdPrint(D_Init, ("Delete Board\n"))
  958. if (NULL == extension)
  959. {
  960. MyKdPrint(D_Error,("Err9X\n"))
  961. return;
  962. }
  963. ++Driver.Stop_Poll; // flag to stop poll access
  964. MyKdPrint(D_Init, ("Delete Ports\n"))
  965. // release any port things
  966. ext = extension->port_ext;
  967. i = 0;
  968. while (ext)
  969. {
  970. del_ext = ext; // kill this one
  971. ext = ext->port_ext; // next in list
  972. SerialCleanupDevice(del_ext); // delete any allocated stuff on ext.
  973. #ifdef NT50
  974. if (del_ext->LowerDeviceObject != NULL)
  975. {
  976. IoDetachDevice(del_ext->LowerDeviceObject);
  977. del_ext->LowerDeviceObject = NULL;
  978. }
  979. #endif
  980. MyKdPrint(D_Init,("RcktDeleteBoard Port Obj:%x\n", del_ext->DeviceObject))
  981. //MyKdPrint(D_Init,(" IrpCnt:%x\n", del_ext->PendingIRPCnt))
  982. IoDeleteDevice(del_ext->DeviceObject);
  983. i++;
  984. }
  985. extension->port_ext = NULL;
  986. MyKdPrint(D_Init,("Deleted %d Ports\n", i))
  987. // release any PDO port things
  988. ext = extension->port_pdo_ext;
  989. i = 0;
  990. while (ext)
  991. {
  992. del_ext = ext; // kill this one
  993. ext = ext->port_ext; // next in list
  994. SerialCleanupDevice(del_ext); // delete any port stuff on ext.
  995. #ifdef NT50
  996. if (del_ext->LowerDeviceObject != NULL)
  997. {
  998. IoDetachDevice(del_ext->LowerDeviceObject);
  999. del_ext->LowerDeviceObject = NULL;
  1000. }
  1001. #endif
  1002. MyKdPrint(D_Init,("RcktDeleteBoard PDO Port Obj:%x\n", del_ext->DeviceObject))
  1003. //MyKdPrint(D_Init,(" IrpCnt:%x\n", del_ext->PendingIRPCnt))
  1004. IoDeleteDevice(del_ext->DeviceObject);
  1005. i++;
  1006. }
  1007. extension->port_pdo_ext = NULL;
  1008. MyKdPrint(D_Init,("Deleted PDO %d Ports\n", i))
  1009. del_ext = NULL;
  1010. // take out of linked list
  1011. ext = Driver.board_ext;
  1012. if (ext == extension) // first in list
  1013. {
  1014. del_ext = extension; // kill this board
  1015. Driver.board_ext = extension->board_ext;
  1016. }
  1017. else
  1018. {
  1019. while (ext)
  1020. {
  1021. if (ext->board_ext == extension) // found in list, so take out of list
  1022. {
  1023. del_ext = extension; // kill this board
  1024. ext->board_ext = extension->board_ext; // link around deleted one
  1025. break;
  1026. }
  1027. ext = ext->board_ext;
  1028. }
  1029. }
  1030. MyKdPrint(D_Init,("Delete board_ext:%x, remaining: %d\n",
  1031. extension, NumDevices()))
  1032. if (del_ext != NULL)
  1033. {
  1034. SerialCleanupDevice(del_ext); // delete any port stuff on ext.
  1035. #ifdef NT50
  1036. if (del_ext->LowerDeviceObject != NULL)
  1037. {
  1038. IoDetachDevice(del_ext->LowerDeviceObject);
  1039. del_ext->LowerDeviceObject = NULL;
  1040. }
  1041. #endif
  1042. MyKdPrint(D_Init,("RcktDeleteBoard Obj:%x\n", del_ext->DeviceObject))
  1043. //MyKdPrint(D_Init,(" IrpCnt:%x\n", del_ext->PendingIRPCnt))
  1044. IoDeleteDevice(del_ext->DeviceObject);
  1045. }
  1046. --Driver.Stop_Poll; // flag to stop poll access
  1047. }
  1048. /*----------------------------------------------------------------------
  1049. RcktDeletePort - This routine will delete a port and is used for
  1050. PnP remove, start handling. I don't think we ever delete PDO's,
  1051. (other than driver unload) here.
  1052. |----------------------------------------------------------------------*/
  1053. VOID RcktDeletePort(IN PSERIAL_DEVICE_EXTENSION extension)
  1054. {
  1055. PSERIAL_DEVICE_EXTENSION ext;
  1056. PSERIAL_DEVICE_EXTENSION del_ext;
  1057. MyKdPrint(D_Init,("RcktDeletePort\n"))
  1058. if (NULL == extension)
  1059. {
  1060. MyKdPrint(D_Error,("Err8X\n"))
  1061. return;
  1062. }
  1063. ++Driver.Stop_Poll; // flag to stop poll access
  1064. MyKdPrint(D_Init, ("Delete Port\n"))
  1065. del_ext = NULL;
  1066. ext = extension->board_ext; // parent board extension
  1067. while (ext)
  1068. {
  1069. if (ext->port_ext == extension) // found the one before it
  1070. {
  1071. del_ext = extension;
  1072. ext->port_ext = extension->port_ext; // skip link to next
  1073. break;
  1074. }
  1075. ext = ext->port_ext;
  1076. }
  1077. if (del_ext != NULL)
  1078. {
  1079. SerialCleanupDevice(del_ext); // delete any port stuff on ext.
  1080. #ifdef NT50
  1081. if (del_ext->LowerDeviceObject != NULL)
  1082. {
  1083. IoDetachDevice(del_ext->LowerDeviceObject);
  1084. del_ext->LowerDeviceObject = NULL;
  1085. }
  1086. #endif
  1087. MyKdPrint(D_Init,("RcktDeletePort Obj:%x\n", del_ext->DeviceObject))
  1088. //MyKdPrint(D_Init,(" IrpCnt:%x\n", del_ext->PendingIRPCnt))
  1089. IoDeleteDevice(del_ext->DeviceObject);
  1090. MyKdPrint(D_Init,("Deleted Port\n"))
  1091. }
  1092. --Driver.Stop_Poll; // flag to stop poll access
  1093. }
  1094. /*----------------------------------------------------------------------
  1095. SerialCleanupDevice -
  1096. This routine will deallocate all of the memory used for
  1097. a particular device. It will also disconnect any resources
  1098. if need be.
  1099. Arguments:
  1100. Extension - Pointer to the device extension which is getting
  1101. rid of all it's resources.
  1102. Return Value:
  1103. None.
  1104. |----------------------------------------------------------------------*/
  1105. VOID SerialCleanupDevice (IN PSERIAL_DEVICE_EXTENSION Extension)
  1106. {
  1107. MyKdPrint(D_Test, ("Mem Alloced Start:%d\n", Driver.mem_alloced))
  1108. ++Driver.Stop_Poll; // flag to stop poll access
  1109. if (Extension)
  1110. {
  1111. if (Extension->DeviceType == DEV_PORT)
  1112. {
  1113. //KeRemoveQueueDpc(&Extension->RocketReadDpc);
  1114. //KeRemoveQueueDpc(&Extension->RocketWriteDpc);
  1115. KeCancelTimer(&Extension->ReadRequestTotalTimer);
  1116. KeCancelTimer(&Extension->ReadRequestIntervalTimer);
  1117. KeCancelTimer(&Extension->WriteRequestTotalTimer);
  1118. KeCancelTimer(&Extension->XoffCountTimer);
  1119. KeRemoveQueueDpc(&Extension->CompleteWriteDpc);
  1120. KeRemoveQueueDpc(&Extension->CompleteReadDpc);
  1121. // Timeout
  1122. KeRemoveQueueDpc(&Extension->TotalReadTimeoutDpc);
  1123. KeRemoveQueueDpc(&Extension->IntervalReadTimeoutDpc);
  1124. KeRemoveQueueDpc(&Extension->TotalWriteTimeoutDpc);
  1125. // Timeout
  1126. KeRemoveQueueDpc(&Extension->CommErrorDpc);
  1127. KeRemoveQueueDpc(&Extension->CommWaitDpc);
  1128. KeRemoveQueueDpc(&Extension->XoffCountTimeoutDpc);
  1129. KeRemoveQueueDpc(&Extension->XoffCountCompleteDpc);
  1130. }
  1131. else // board device
  1132. {
  1133. #ifdef S_VS
  1134. if (Extension->hd)
  1135. {
  1136. hdlc_close(Extension->hd);
  1137. our_free(Extension->hd, "Dhd");
  1138. Extension->hd = NULL;
  1139. }
  1140. if (Extension->pm)
  1141. {
  1142. portman_close(Extension->pm);
  1143. our_free(Extension->pm,"Dpm");
  1144. Extension->pm = NULL;
  1145. }
  1146. #endif
  1147. #ifdef S_RK
  1148. if (Extension->io_reported) // tells that we should deallocate on unload.
  1149. {
  1150. SerialUnReportResourcesDevice(Extension); // give back io,irq resources
  1151. Extension->io_reported = 0;
  1152. }
  1153. if (Extension->CtlP)
  1154. {
  1155. ExFreePool(Extension->CtlP);
  1156. Extension->CtlP = NULL;
  1157. }
  1158. #endif
  1159. // free board config if present
  1160. if (Extension->config)
  1161. {
  1162. ExFreePool(Extension->config);
  1163. Extension->config = NULL;
  1164. }
  1165. } // board dev
  1166. // Get rid of all external naming as well as removing
  1167. // the device map entry.
  1168. SerialCleanupExternalNaming(Extension);
  1169. } // if not a null extension
  1170. MyKdPrint(D_Test, ("Mem Alloced End:%d\n", Driver.mem_alloced))
  1171. --Driver.Stop_Poll; // flag to stop poll access
  1172. }
  1173. #ifdef S_RK
  1174. /*------------------------------------------------------------------
  1175. SerialGetMappedAddress -
  1176. This routine maps an IO address to system address space.
  1177. Arguments:
  1178. BusType - what type of bus - eisa, mca, isa
  1179. IoBusNumber - which IO bus (for machines with multiple buses).
  1180. IoAddress - base device address to be mapped.
  1181. NumberOfBytes - number of bytes for which address is valid.
  1182. AddressSpace - Denotes whether the address is in io space or memory.
  1183. MappedAddress - indicates whether the address was mapped.
  1184. This only has meaning if the address returned
  1185. is non-null.
  1186. Return Value:
  1187. Mapped address
  1188. ----------------------------------------------------------------------*/
  1189. PVOID SerialGetMappedAddress(
  1190. IN INTERFACE_TYPE BusType,
  1191. IN ULONG BusNumber,
  1192. PHYSICAL_ADDRESS IoAddress,
  1193. ULONG NumberOfBytes,
  1194. ULONG AddressSpace,
  1195. PBOOLEAN MappedAddress,
  1196. BOOLEAN DoTranslation)
  1197. {
  1198. PHYSICAL_ADDRESS cardAddress;
  1199. PVOID address;
  1200. if (DoTranslation)
  1201. {
  1202. if(!HalTranslateBusAddress(
  1203. BusType,
  1204. BusNumber,
  1205. IoAddress,
  1206. &AddressSpace,
  1207. &cardAddress)){
  1208. // if the translate address call failed return null so we don't load
  1209. address = NULL;
  1210. return address;
  1211. }
  1212. }
  1213. else
  1214. {
  1215. cardAddress = IoAddress;
  1216. }
  1217. // Map the device base address into the virtual address space
  1218. // if the address is in memory space.
  1219. if (!AddressSpace) {
  1220. address = MmMapIoSpace(cardAddress,
  1221. NumberOfBytes,
  1222. FALSE);
  1223. *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE));
  1224. }
  1225. else
  1226. {
  1227. address = (PVOID)cardAddress.LowPart;
  1228. *MappedAddress = FALSE;
  1229. }
  1230. return address;
  1231. }
  1232. #endif
  1233. /*------------------------------------------------------------------
  1234. Routine Description:
  1235. This routine will be used to create a symbolic link
  1236. to the driver name in the given object directory.
  1237. It will also create an entry in the device map for
  1238. this device - IF we could create the symbolic link.
  1239. Arguments:
  1240. Extension - Pointer to the device extension.
  1241. Return Value:
  1242. None.
  1243. -------------------------------------------------------------------*/
  1244. VOID SerialSetupExternalNaming (IN PSERIAL_DEVICE_EXTENSION Extension)
  1245. {
  1246. char full_ntname[50];
  1247. char full_comname[40];
  1248. NTSTATUS status;
  1249. strcpy(full_ntname, szDevice); // "\\Device\\"
  1250. strcat(full_ntname, Extension->NtNameForPort); // "Rocket#"
  1251. strcpy(full_comname, szDosDevices); // "\\DosDevices\\"
  1252. strcat(full_comname, Extension->SymbolicLinkName); // "COM#"
  1253. MyKdPrint(D_Init,("SetupExtName:%s\n", Extension->SymbolicLinkName))
  1254. status = IoCreateSymbolicLink(
  1255. CToU2(full_comname), // like "\\DosDevices\\COM5"
  1256. CToU1(full_ntname)); // like "\\Device\\RocketPort0"
  1257. if (NT_SUCCESS(status)) {
  1258. MyKdPrint( D_Init, ("Symbolic link %s created\n", full_comname ))
  1259. }
  1260. else {
  1261. MyKdPrint(D_Init,("Err SymLnkCreate.\n"))
  1262. // Oh well, couldn't create the symbolic link. No point
  1263. // in trying to create the device map entry.
  1264. SerialLogError(
  1265. Extension->DeviceObject->DriverObject,
  1266. Extension->DeviceObject,
  1267. 0,
  1268. 0,
  1269. 0,
  1270. ErrNum++,
  1271. status,
  1272. SERIAL_NO_SYMLINK_CREATED,
  1273. CToU1(Extension->SymbolicLinkName)->Length+sizeof(WCHAR),
  1274. CToU1(Extension->SymbolicLinkName)->Buffer);
  1275. return;
  1276. }
  1277. Extension->CreatedSymbolicLink = TRUE;
  1278. // Add entry to let system and apps know about our ports
  1279. // after V3.23 I added "\device\" into the registry entry(this was wrong)
  1280. // 1-26-99, bugfix, don't add "\device\" into the registry entry,
  1281. // this is not what serial.sys does. kpb.
  1282. status = RtlWriteRegistryValue(
  1283. RTL_REGISTRY_DEVICEMAP,
  1284. L"SERIALCOMM",
  1285. CToU2(Extension->NtNameForPort)->Buffer, // "RocketPort0"
  1286. //CToU2(full_ntname)->Buffer, // "\Device\Vslinka0"
  1287. REG_SZ,
  1288. CToU1(Extension->SymbolicLinkName)->Buffer, // COM#
  1289. CToU1(Extension->SymbolicLinkName)->Length+sizeof(WCHAR));
  1290. if (!NT_SUCCESS(status))
  1291. {
  1292. MyKdPrint(D_Init,("GenError C2.\n"))
  1293. SerialLogError(Extension->DeviceObject->DriverObject,
  1294. Extension->DeviceObject,
  1295. 0,
  1296. 0,
  1297. 0,
  1298. ErrNum++,
  1299. status,
  1300. SERIAL_NO_DEVICE_MAP_CREATED,
  1301. CToU1(Extension->SymbolicLinkName)->Length+sizeof(WCHAR),
  1302. CToU1(Extension->SymbolicLinkName)->Buffer);
  1303. }
  1304. }
  1305. /*---------------------------------------------------------------------
  1306. SerialCleanupExternalNaming -
  1307. This routine will be used to delete a symbolic link
  1308. to the driver name in the given object directory.
  1309. It will also delete an entry in the device map for
  1310. this device if the symbolic link had been created.
  1311. Arguments:
  1312. Extension - Pointer to the device extension.
  1313. |----------------------------------------------------------------------*/
  1314. VOID SerialCleanupExternalNaming(IN PSERIAL_DEVICE_EXTENSION Extension)
  1315. {
  1316. char name[60];
  1317. NTSTATUS status;
  1318. // We're cleaning up here. One reason we're cleaning up
  1319. // is that we couldn't allocate space for the directory
  1320. // name or the symbolic link.
  1321. if (Extension->CreatedSymbolicLink)
  1322. {
  1323. MyKdPrint(D_Init,("KillSymLink:%s\n", Extension->SymbolicLinkName))
  1324. strcpy(name, szDosDevices); // "\\DosDevices\\"
  1325. strcat(name, Extension->SymbolicLinkName); // like "COM5"
  1326. IoDeleteSymbolicLink(CToU1(name));
  1327. #ifdef NT50
  1328. // Only for ports!
  1329. if (Extension->DeviceType == DEV_PORT &&
  1330. &Extension->DeviceClassSymbolicName != NULL &&
  1331. Extension->DeviceClassSymbolicName.Buffer != NULL) {
  1332. MyKdPrint(D_Init,("KillInterface:%s\n",
  1333. UToC1(&Extension->DeviceClassSymbolicName)))
  1334. status = IoSetDeviceInterfaceState( &Extension->DeviceClassSymbolicName, FALSE );
  1335. if (!NT_SUCCESS(status)) {
  1336. MyKdPrint(D_Error,("Couldn't clear class association for %s\n",
  1337. UToC1(&Extension->DeviceClassSymbolicName)))
  1338. }
  1339. else {
  1340. MyKdPrint(D_Init, ("Cleared class association for device: %s\n",
  1341. UToC1(&Extension->DeviceClassSymbolicName)))
  1342. }
  1343. RtlFreeUnicodeString( &Extension->DeviceClassSymbolicName );
  1344. Extension->DeviceClassSymbolicName.Buffer = NULL;
  1345. }
  1346. #endif
  1347. Extension->CreatedSymbolicLink = 0;
  1348. }
  1349. if (Extension->DeviceType == DEV_PORT)
  1350. {
  1351. // Delete any reg entry to let system and apps know about our ports
  1352. strcpy(name, szDevice); // "\\Device\\"
  1353. strcat(name, Extension->NtNameForPort); // "Rocket#"
  1354. status = RtlDeleteRegistryValue(
  1355. RTL_REGISTRY_DEVICEMAP,
  1356. L"SERIALCOMM",
  1357. CToU1(Extension->NtNameForPort)->Buffer); // "RocketPort0"
  1358. //CToU1(name)->Buffer);
  1359. MyKdPrint(D_Init, ("RtlDeleteRegistryValue:%s\n",Extension->NtNameForPort))
  1360. #if NT50
  1361. // Make sure the ComDB binary data is cleared for the specific port. There
  1362. // are some problems with W2000 PnP Manager taking care of this in every
  1363. // circumstance.
  1364. (void)clear_com_db( Extension->SymbolicLinkName );
  1365. #endif
  1366. }
  1367. }
  1368. /*-----------------------------------------------------------------------
  1369. SerialLogError -
  1370. This routine allocates an error log entry, copies the supplied data
  1371. to it, and requests that it be written to the error log file.
  1372. Arguments:
  1373. DriverObject - A pointer to the driver object for the device.
  1374. DeviceObject - A pointer to the device object associated with the
  1375. device that had the error, early in initialization, one may not
  1376. yet exist.
  1377. P1,P2 - If phyical addresses for the controller ports involved
  1378. with the error are available, put them through as dump data.
  1379. SequenceNumber - A ulong value that is unique to an IRP over the
  1380. life of the irp in this driver - 0 generally means an error not
  1381. associated with an irp.
  1382. MajorFunctionCode - If there is an error associated with the irp,
  1383. this is the major function code of that irp.
  1384. RetryCount - The number of times a particular operation has been
  1385. retried.
  1386. UniqueErrorValue - A unique long word that identifies the particular
  1387. call to this function.
  1388. FinalStatus - The final status given to the irp that was associated
  1389. with this error. If this log entry is being made during one of
  1390. the retries this value will be STATUS_SUCCESS.
  1391. SpecificIOStatus - The IO status for a particular error.
  1392. LengthOfInsert1 - The length in bytes (including the terminating NULL)
  1393. of the first insertion string.
  1394. Return Value:
  1395. None.
  1396. |-----------------------------------------------------------------------*/
  1397. VOID SerialLogError(
  1398. IN PDRIVER_OBJECT DriverObject,
  1399. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  1400. IN ULONG SequenceNumber,
  1401. IN UCHAR MajorFunctionCode,
  1402. IN UCHAR RetryCount,
  1403. IN ULONG UniqueErrorValue,
  1404. IN NTSTATUS FinalStatus,
  1405. IN NTSTATUS SpecificIOStatus,
  1406. IN ULONG LengthOfInsert1,
  1407. IN PWCHAR Insert1)
  1408. {
  1409. PIO_ERROR_LOG_PACKET errorLogEntry;
  1410. PVOID objectToUse;
  1411. PUCHAR ptrToFirstInsert;
  1412. if (DeviceObject != NULL)
  1413. objectToUse = DeviceObject;
  1414. else
  1415. objectToUse = DriverObject;
  1416. errorLogEntry = IoAllocateErrorLogEntry(
  1417. objectToUse,
  1418. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + LengthOfInsert1));
  1419. if ( errorLogEntry == NULL)
  1420. {
  1421. MyKdPrint(D_Init,("SerialLogErr, Err A size:%d obj:%x\n",
  1422. LengthOfInsert1,objectToUse))
  1423. return;
  1424. }
  1425. errorLogEntry->ErrorCode = SpecificIOStatus;
  1426. errorLogEntry->SequenceNumber = SequenceNumber;
  1427. errorLogEntry->MajorFunctionCode = MajorFunctionCode;
  1428. errorLogEntry->RetryCount = RetryCount;
  1429. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  1430. errorLogEntry->FinalStatus = FinalStatus;
  1431. errorLogEntry->DumpDataSize = 0;
  1432. ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
  1433. if (LengthOfInsert1)
  1434. {
  1435. errorLogEntry->NumberOfStrings = 1;
  1436. errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
  1437. (PUCHAR)errorLogEntry);
  1438. RtlCopyMemory(ptrToFirstInsert,
  1439. Insert1,
  1440. LengthOfInsert1);
  1441. }
  1442. IoWriteErrorLogEntry(errorLogEntry);
  1443. }
  1444. /*-----------------------------------------------------------------------
  1445. EventLog - To put a shell around the SerialLogError to make calls easier
  1446. to use.
  1447. |-----------------------------------------------------------------------*/
  1448. VOID EventLog(
  1449. IN PDRIVER_OBJECT DriverObject,
  1450. IN NTSTATUS FinalStatus,
  1451. IN NTSTATUS SpecificIOStatus,
  1452. IN ULONG LengthOfInsert1,
  1453. IN PWCHAR Insert1)
  1454. {
  1455. SerialLogError(
  1456. DriverObject,
  1457. NULL,
  1458. 0,
  1459. 0,
  1460. 0,
  1461. ErrNum++,
  1462. FinalStatus,
  1463. SpecificIOStatus,
  1464. LengthOfInsert1,
  1465. Insert1);
  1466. return;
  1467. }
  1468. /*-----------------------------------------------------------------------
  1469. InitPortsSettings - Read registry default Port setting
  1470. |-----------------------------------------------------------------------*/
  1471. VOID InitPortsSettings(IN PSERIAL_DEVICE_EXTENSION extension)
  1472. {
  1473. RTL_QUERY_REGISTRY_TABLE paramTable[2];
  1474. #define MAX_STRING 256
  1475. WCHAR StrValBuf[MAX_STRING+1];
  1476. char comname[20];
  1477. UNICODE_STRING USReturn;
  1478. USReturn.Buffer = NULL;
  1479. RtlInitUnicodeString(&USReturn, NULL);
  1480. USReturn.MaximumLength = sizeof(WCHAR)*MAX_STRING;
  1481. USReturn.Buffer = StrValBuf;
  1482. if(strlen(extension->SymbolicLinkName) < sizeof(comname))
  1483. {
  1484. strncpy(comname, extension->SymbolicLinkName, strlen(extension->SymbolicLinkName) + 1);
  1485. strcat(comname, ":");
  1486. }
  1487. RtlZeroMemory(&paramTable[0],sizeof(paramTable));
  1488. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1489. paramTable[0].Name = CToU1(comname)->Buffer;
  1490. paramTable[0].EntryContext = &USReturn;
  1491. paramTable[0].DefaultType = REG_SZ;
  1492. paramTable[0].DefaultData = L"";
  1493. paramTable[0].DefaultLength = 0;
  1494. if (!NT_SUCCESS(RtlQueryRegistryValues(
  1495. // \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion
  1496. RTL_REGISTRY_WINDOWS_NT,
  1497. L"Ports",
  1498. &paramTable[0],
  1499. NULL,
  1500. NULL
  1501. )))
  1502. {
  1503. // no entry
  1504. return;
  1505. }
  1506. // Check for data, indicates settings exist for COMX
  1507. if (USReturn.Length == 0)
  1508. {
  1509. // no entry
  1510. return;
  1511. }
  1512. #define TOKENS 5
  1513. #define MAX_DIGITS 6
  1514. {
  1515. unsigned int TokenCounter;
  1516. unsigned int CharCounter;
  1517. unsigned int LastCount;
  1518. WCHAR *TokenPtrs[TOKENS];
  1519. ULONG BaudRateValue;
  1520. // Make sure all Token ptrs point to NULL
  1521. for(TokenCounter = 0; TokenCounter < TOKENS; TokenCounter++)
  1522. TokenPtrs[TokenCounter] = NULL;
  1523. // init counters
  1524. TokenCounter = 0;
  1525. LastCount = 0;
  1526. for(CharCounter = 0; CharCounter < USReturn.Length; CharCounter++)
  1527. {
  1528. if(StrValBuf[CharCounter] == ',')
  1529. {
  1530. StrValBuf[CharCounter] = '\0'; //Null terminate DbgPrint
  1531. TokenPtrs[TokenCounter++] = &StrValBuf[LastCount];
  1532. //point to beginning of next string
  1533. LastCount = CharCounter +1;
  1534. }
  1535. }
  1536. // set up the last token
  1537. if(CharCounter < MAX_STRING)
  1538. StrValBuf[CharCounter] = '\0'; //Null terminate DbgPrint NULL
  1539. if(TokenCounter < TOKENS)
  1540. TokenPtrs[TokenCounter] = &StrValBuf[LastCount];
  1541. // token 0: baud rate
  1542. if(TokenPtrs[0] != NULL)
  1543. {
  1544. BaudRateValue = 0;
  1545. CharCounter = 0;
  1546. while( (TokenPtrs[0][CharCounter] != '\0') && //DbgPrint NULL
  1547. (CharCounter < MAX_DIGITS) &&
  1548. (BaudRateValue != ~0x0L) )
  1549. {
  1550. BaudRateValue *= 10;
  1551. switch(TokenPtrs[0][CharCounter++])
  1552. {
  1553. case '0': break;
  1554. case '1': BaudRateValue += 1; break;
  1555. case '2': BaudRateValue += 2; break;
  1556. case '3': BaudRateValue += 3; break;
  1557. case '4': BaudRateValue += 4; break;
  1558. case '5': BaudRateValue += 5; break;
  1559. case '6': BaudRateValue += 6; break;
  1560. case '7': BaudRateValue += 7; break;
  1561. case '8': BaudRateValue += 8; break;
  1562. case '9': BaudRateValue += 9; break;
  1563. default: BaudRateValue = ~0x0UL; break;
  1564. }
  1565. }
  1566. if ((BaudRateValue >= 50) && (BaudRateValue <= 460800))
  1567. extension->BaudRate = BaudRateValue; // allow any baud rate
  1568. #ifdef COMMENT_OUT
  1569. switch (BaudRateValue)
  1570. {
  1571. // Valid baud rates
  1572. case 50: case 75: case 110:
  1573. case 134: case 150: case 200:
  1574. case 300: case 600: case 1200:
  1575. case 1800: case 2400: case 4800:
  1576. case 7200: case 9600: case 19200:
  1577. case 38400: case 57600: case 76800:
  1578. case 115200: case 230400: case 460800:
  1579. extension->BaudRate = BaudRateValue;
  1580. break;
  1581. default:
  1582. // Selected baud rate not available for RocketPort COMX
  1583. break;
  1584. }
  1585. #endif
  1586. }
  1587. // token 1: parity
  1588. if(TokenPtrs[1] != NULL)
  1589. {
  1590. switch (TokenPtrs[1][0])
  1591. {
  1592. case 'n':
  1593. extension->LineCtl.Parity = NO_PARITY;
  1594. break;
  1595. case 'o':
  1596. extension->LineCtl.Parity = ODD_PARITY;
  1597. break;
  1598. case 'e':
  1599. extension->LineCtl.Parity = EVEN_PARITY;
  1600. break;
  1601. default:
  1602. // Selected parity not available for RocketPort COMX
  1603. break;
  1604. }
  1605. }
  1606. // token 2: data bits
  1607. if(TokenPtrs[2] != NULL)
  1608. {
  1609. switch (TokenPtrs[2][0])
  1610. {
  1611. case '7':
  1612. extension->LineCtl.WordLength = 7;
  1613. break;
  1614. case '8':
  1615. extension->LineCtl.WordLength = 8;
  1616. break;
  1617. default:
  1618. // Selected databits not available for RocketPort COMX
  1619. break;
  1620. }
  1621. }
  1622. // token 3: Stop bits
  1623. if(TokenPtrs[3] != NULL)
  1624. {
  1625. switch (TokenPtrs[3][0])
  1626. {
  1627. case '1':
  1628. extension->LineCtl.StopBits = STOP_BIT_1;
  1629. break;
  1630. case '2':
  1631. extension->LineCtl.StopBits = STOP_BITS_2;
  1632. break;
  1633. default:
  1634. break;
  1635. }
  1636. }
  1637. // token 4: flow control: rts/cts or XON/XOFF
  1638. if(TokenPtrs[4] != NULL)
  1639. {
  1640. switch (TokenPtrs[4][0])
  1641. {
  1642. case 'x': // XON/XOFF f/c
  1643. extension->HandFlow.FlowReplace |=
  1644. (SERIAL_AUTO_TRANSMIT | SERIAL_AUTO_RECEIVE) ;
  1645. break;
  1646. case 'p': // RTS/CTS f/c
  1647. extension->HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
  1648. extension->HandFlow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
  1649. extension->HandFlow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
  1650. break;
  1651. default:
  1652. break;
  1653. } // Selected flowcontrol not available for RocketPort COMX
  1654. } // flow control token
  1655. }
  1656. }
  1657. /*----------------------------------------------------------------------
  1658. CheckPortName - If the name is already used, then derive one that is
  1659. not in use.
  1660. name - name of port to check. Modify if a problem.
  1661. Return - 0=name ok, 1=generated modified name, other= error.
  1662. |----------------------------------------------------------------------*/
  1663. static int CheckPortName(IN OUT char *name,
  1664. IN PSERIAL_DEVICE_EXTENSION extension)
  1665. {
  1666. int i;
  1667. char prefix[20];
  1668. int num;
  1669. int new_name_given = 0;
  1670. MyKdPrint(D_Init, ("CheckPortName:%s\n", name));
  1671. // if no name, give a reasonable default.
  1672. if (name[0] == 0)
  1673. {
  1674. new_name_given = 1; // flag it
  1675. strcpy(name, "COM3");
  1676. }
  1677. // load prefix(such as "COM" from "COM25" from name)
  1678. i = 0;
  1679. while ( (!our_isdigit(name[i])) && (name[i] != 0) && (i < 18))
  1680. {
  1681. prefix[i] = name[i];
  1682. ++i;
  1683. }
  1684. prefix[i] = 0;
  1685. // now grab post-fix number value incase we need to derive a new name
  1686. num = 0;
  1687. if (our_isdigit(name[i]))
  1688. num = getint(&name[i], NULL);
  1689. i = 0;
  1690. for (;;)
  1691. {
  1692. // if we are already using this name, or if its in the registry
  1693. if ((find_ext_by_name(name, NULL) != NULL) ||
  1694. (IsPortNameInHardwareMap(name)) )
  1695. {
  1696. // name already in use, so derive a new one
  1697. new_name_given = 1; // flag it
  1698. ++num; // give a new post-fix index(so "COM4" to "COM5")
  1699. Sprintf(name, "%s%d", prefix, num);
  1700. }
  1701. else
  1702. { // name is ok
  1703. if (new_name_given)
  1704. {
  1705. MyKdPrint(D_Init, ("Form new name:%s\n", name))
  1706. }
  1707. return new_name_given; // return 0 if no change made, 1 if changed
  1708. }
  1709. ++i;
  1710. if (i > 5000)
  1711. {
  1712. // problems
  1713. return 2; // return error
  1714. }
  1715. }
  1716. }
  1717. /*----------------------------------------------------------------------
  1718. IsPortNameInHardwareMap - For Pnp operation, we startup before configuration,
  1719. so pick a reasonable starting com-port name. We do this by finding
  1720. registry entries for all existing com-ports in the system. This
  1721. info is used to determine a name for the port.
  1722. |----------------------------------------------------------------------*/
  1723. static int IsPortNameInHardwareMap(char *name)
  1724. {
  1725. static char *szRegRMHDS =
  1726. {"\\Registry\\Machine\\Hardware\\DeviceMap\\SerialComm"};
  1727. HANDLE KeyHandle = NULL;
  1728. ULONG data_type;
  1729. int node_num = 0;
  1730. char buffer[200];
  1731. char KeyNameStr[60];
  1732. char *data_ptr;
  1733. int stat;
  1734. //MyKdPrint(D_Init, ("IsPortNameInHardwareMap\n"))
  1735. stat = our_open_key(&KeyHandle, NULL, szRegRMHDS, KEY_READ);
  1736. if (stat)
  1737. {
  1738. MyKdPrint(D_Init, ("Failed OpenKey\n"))
  1739. return 0; // return no name clash
  1740. }
  1741. KeyNameStr[0] = 0;
  1742. for(;;)
  1743. {
  1744. stat = our_enum_value(KeyHandle,
  1745. node_num,
  1746. buffer,
  1747. 200,
  1748. &data_type,
  1749. &data_ptr,
  1750. KeyNameStr);
  1751. ++node_num;
  1752. if (stat)
  1753. {
  1754. //MyKdPrint(D_Init, ("Done\n"))
  1755. break;
  1756. }
  1757. //MyKdPrint(D_Init, ("Got Value:%s\n", KeyNameStr))
  1758. if (data_type != REG_SZ)
  1759. {
  1760. MyKdPrint(D_Init, ("Not RegSZ\n"))
  1761. break;
  1762. }
  1763. WStrToCStr(KeyNameStr, (PWCHAR)data_ptr, 18);
  1764. //MyKdPrint(D_Init, ("KeyFound:%s\n", KeyNameStr))
  1765. if (my_lstricmp(KeyNameStr, name) == 0) // match
  1766. {
  1767. // we got trouble, our name matches one already in registry
  1768. //MyKdPrint(D_Init, ("Not a good name.\n"))
  1769. return 1; // err: name clash
  1770. }
  1771. }
  1772. return 0; // ok, no name clash
  1773. }
  1774. /*----------------------------------------------------------------------
  1775. RcktInitPollTimer - Initialize the poll timer for no interrupt operation.
  1776. The fastest we can poll seems to be 10ms under NT.
  1777. |----------------------------------------------------------------------*/
  1778. NTSTATUS RcktInitPollTimer(void)
  1779. {
  1780. MyKdPrint(D_Init,("RcktInitPollTimer\n"))
  1781. KeInitializeDpc(&Driver.TimerDpc, TimerDpc, NULL);
  1782. KeInitializeTimer(&Driver.PollTimer);
  1783. // ScanRate is registry option in MS units.
  1784. if (Driver.ScanRate < 1) Driver.ScanRate = 1;
  1785. if (Driver.ScanRate > 40) Driver.ScanRate = 40;
  1786. // NT Interval unit is 100nsec so to get Freq polls/sec
  1787. Driver.PollIntervalTime.QuadPart = Driver.ScanRate * -10000;
  1788. #ifdef S_VS
  1789. Driver.Tick100usBase = 100; // 100us base units(typical:100)
  1790. Driver.TickBaseCnt = Driver.ScanRate * 10;
  1791. KeQuerySystemTime(&Driver.IsrSysTime);
  1792. KeQuerySystemTime(&Driver.LastIsrSysTime);
  1793. #endif
  1794. Driver.TimerCreated = 1; // tells to deallocate
  1795. return STATUS_SUCCESS;
  1796. }
  1797. /*-----------------------------------------------------------------------
  1798. InitSocketModems -
  1799. This function is responsible for clearing the initial reset state on
  1800. any device with SocketModems and initializing the location information
  1801. (ROW) for each SocketModem on the device. We only initialize extensions
  1802. for which the device extension has the ModemDevice field enabled in
  1803. the config information. VS2000 devices don't need to be cleared from
  1804. reset since the firmware does that.
  1805. |-----------------------------------------------------------------------*/
  1806. void InitSocketModems(PSERIAL_DEVICE_EXTENSION ext)
  1807. {
  1808. DEVICE_CONFIG *cfg = ext->config;
  1809. PSERIAL_DEVICE_EXTENSION portex,head_portex;
  1810. MyKdPrint(D_Init,("InitSocketModems\n"))
  1811. // use the PDO port list, if present since they start up first under nt5
  1812. head_portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  1813. if (!cfg->ModemDevice) return;
  1814. #ifdef S_RK
  1815. /*
  1816. RMII boards don't require ROW codes set...
  1817. */
  1818. if (
  1819. ((cfg->PCI_DevID == PCI_DEVICE_RMODEM6)
  1820. ||
  1821. (cfg->PCI_DevID == PCI_DEVICE_RMODEM4))
  1822. &&
  1823. (cfg->PCI_RevID == PCI_REVISION_RMODEM_II)
  1824. )
  1825. return;
  1826. #ifdef MDM_RESET
  1827. // in case the modems are hung up, we'd like server reloads to clear them
  1828. // up...so, even though it's likely the modems are in reset state already,
  1829. // put them there again...
  1830. portex = head_portex;
  1831. while (portex)
  1832. {
  1833. ModemReset(portex,1);
  1834. portex = portex->port_ext;
  1835. }
  1836. // allow the socketmodems to reset...
  1837. time_stall(Driver.MdmSettleTime);
  1838. #endif
  1839. // clear the ports on the board from the reset state
  1840. portex = head_portex;
  1841. while (portex)
  1842. {
  1843. ModemReset(portex, 0);
  1844. portex = portex->port_ext;
  1845. }
  1846. // allow the socketmodems to settle after clearing them from reset
  1847. time_stall(Driver.MdmSettleTime);
  1848. #endif
  1849. time_stall(20);
  1850. /*
  1851. send the localization string (ROW) to each socketmodem, whether internal
  1852. or external (VS2000)...
  1853. */
  1854. portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  1855. while (portex) {
  1856. ModemWriteROW(portex, Driver.MdmCountryCode);
  1857. portex = portex->port_ext;
  1858. }
  1859. MyKdPrint(D_Init,("InitSocketModems: exit\n"))
  1860. }
  1861. #ifdef TRYED_IT_WORKED_REALLY_BAD
  1862. /*-----------------------------------------------------------------------
  1863. DumpTracefile -
  1864. |-----------------------------------------------------------------------*/
  1865. static int DumpTracefile(void)
  1866. {
  1867. NTSTATUS ntStatus;
  1868. HANDLE NtFileHandle;
  1869. OBJECT_ATTRIBUTES ObjectAttributes;
  1870. IO_STATUS_BLOCK IoStatus;
  1871. USTR_160 uname;
  1872. FILE_STANDARD_INFORMATION StandardInfo;
  1873. //ULONG LengthOfFile;
  1874. static char *def_filename = {"\\SystemRoot\\system32\\VSLINKA\\trace.txt"};
  1875. BYTE *buf;
  1876. buf = our_locked_alloc(1010,"dump");
  1877. CToUStr((PUNICODE_STRING)&uname, def_filename, sizeof(uname));
  1878. InitializeObjectAttributes ( &ObjectAttributes,
  1879. &uname.ustr,
  1880. OBJ_CASE_INSENSITIVE,
  1881. NULL,
  1882. NULL );
  1883. #ifdef COMMENT_OUT
  1884. ntStatus = ZwCreateFile( &NtFileHandle,
  1885. SYNCHRONIZE | FILE_WRITE_DATA | FILE_APPEND_DATA,
  1886. // GENERIC_WRITE | SYNCHRONIZE,
  1887. &ObjectAttributes,
  1888. &IoStatus,
  1889. NULL, // alloc size = none
  1890. FILE_ATTRIBUTE_NORMAL,
  1891. FILE_SHARE_WRITE,
  1892. FILE_SUPERSEDE,
  1893. FILE_SYNCHRONOUS_IO_NONALERT,
  1894. NULL, // eabuffer
  1895. 0); // ealength
  1896. if (!NT_SUCCESS(ntStatus))
  1897. {
  1898. Eprintf("Dump Error B");
  1899. our_free(buf, "dump");
  1900. return 1;
  1901. }
  1902. // Write the file from our buffer.
  1903. ntStatus = ZwWriteFile(NtFileHandle,
  1904. NULL,NULL,NULL,
  1905. &IoStatus,
  1906. "Start of file> ",
  1907. 14,
  1908. FILE_WRITE_TO_END_OF_FILE, NULL);
  1909. while (!q_empty(&Driver.DebugQ))
  1910. {
  1911. int q_cnt;
  1912. q_cnt = q_count(&Driver.DebugQ);
  1913. if (q_cnt > 1000)
  1914. q_cnt = 1000;
  1915. q_get(&Driver.DebugQ, buf, q_cnt);
  1916. // Write the file from our buffer.
  1917. ntStatus = ZwWriteFile(NtFileHandle,
  1918. NULL,NULL,NULL,
  1919. &IoStatus,
  1920. buf,
  1921. q_cnt,
  1922. FILE_WRITE_TO_END_OF_FILE, NULL);
  1923. }
  1924. if (!NT_SUCCESS(ntStatus))
  1925. Eprintf("Dump Error A:%d",ntStatus);
  1926. ZwClose(NtFileHandle);
  1927. #endif
  1928. our_free(buf, "dump");
  1929. return 0;
  1930. }
  1931. #endif
  1932. /********************************************************************
  1933. RocketModem II loader stuff...
  1934. ********************************************************************/
  1935. #ifdef S_RK
  1936. /*
  1937. responses are forced to upper case for ease in checking (response case
  1938. varies depending on whether the modem was loaded already or not...
  1939. */
  1940. #define MODEM_LOADCHECK_CMD "ATI3\r"
  1941. #define MODEM_RESET_CMD "ATZ0\r"
  1942. #define MODEM_LOAD_CMD "AT**\r"
  1943. #define MODEM_LOADCHECK_RESP "V2.101A2-V90_2M_DLS_RAM\r\n"
  1944. #define DOWNLOAD_INITIATED_RESP "DOWNLOAD INITIATED ..\r\n"
  1945. #define CSM_READY_RESP "115.2K\r\n"
  1946. #define FIRMWARE_READY_RESP "DEVICE SUCCESSFULLY PROGRAMMED\r\nCHECKSUM: "
  1947. #define OK_RESP "OK"
  1948. /**********************************************************************
  1949. send ATI3 to determine if modem is loaded...
  1950. **********************************************************************/
  1951. static int
  1952. RM_Snd_ATI3_Command(MODEM_STATE *pModemState)
  1953. {
  1954. /*
  1955. discard any data currently in the receive FIFO...
  1956. */
  1957. if (RxFIFOReady(pModemState->portex)) {
  1958. pModemState->status = RMODEM_FAILED;
  1959. Eprintf("Warning: Modem on %s overrun",
  1960. pModemState->portex->SymbolicLinkName);
  1961. return(0);
  1962. }
  1963. SEND_CMD_STRING(pModemState->portex,MODEM_LOADCHECK_CMD);
  1964. return(1);
  1965. }
  1966. /**********************************************************************
  1967. check response to ATI3 - modem loaded or unloaded...
  1968. **********************************************************************/
  1969. static int
  1970. RM_Rcv_ATI3_Response(MODEM_STATE *pModemState)
  1971. {
  1972. int index;
  1973. index = READ_RESPONSE_STRINGS(pModemState->portex,
  1974. OK_RESP,
  1975. MODEM_LOADCHECK_RESP,
  1976. ONE_SECOND);
  1977. switch (index) {
  1978. /*
  1979. loaded with the firmware revision this release of RocketPort NT driver expects...
  1980. */
  1981. case 0: {
  1982. pModemState->status = RMODEM_NOT_LOADED;
  1983. break;
  1984. }
  1985. case 1: {
  1986. pModemState->status = RMODEM_LOADED;
  1987. break;
  1988. }
  1989. default: {
  1990. /*
  1991. either it didn't respond, or responded with the wrong string. either way,
  1992. we'll reset it (again) and then reload it...
  1993. */
  1994. pModemState->status = RMODEM_FAILED;
  1995. Eprintf("Warning: Modem on %s no response (I3)",
  1996. pModemState->portex->SymbolicLinkName);
  1997. return(0);
  1998. }
  1999. }
  2000. return(1);
  2001. }
  2002. /**********************************************************************
  2003. response to AT** command received...
  2004. **********************************************************************/
  2005. static int
  2006. RM_Rcv_ModemLoad_Response(MODEM_STATE *pModemState)
  2007. {
  2008. int index;
  2009. index = READ_RESPONSE_STRING(
  2010. pModemState->portex,
  2011. DOWNLOAD_INITIATED_RESP,
  2012. FIVE_SECONDS);
  2013. if (index) {
  2014. pModemState->status = RMODEM_FAILED;
  2015. Eprintf("Warning: Modem on %s no response (LL)",
  2016. pModemState->portex->SymbolicLinkName);
  2017. return(0);
  2018. }
  2019. return(1);
  2020. }
  2021. /**********************************************************************
  2022. CSM loaded response...
  2023. **********************************************************************/
  2024. static int
  2025. RM_Rcv_FirmwareLoader_Loaded(MODEM_STATE *pModemState)
  2026. {
  2027. int index;
  2028. index = READ_RESPONSE_STRING(
  2029. pModemState->portex,
  2030. CSM_READY_RESP,
  2031. FIVE_SECONDS);
  2032. if (index) {
  2033. pModemState->status = RMODEM_FAILED;
  2034. Eprintf("Warning: Modem on %s no response (FL)",
  2035. pModemState->portex->SymbolicLinkName);
  2036. return(0);
  2037. }
  2038. return(1);
  2039. }
  2040. /**********************************************************************
  2041. check if firmware loaded successfully...
  2042. **********************************************************************/
  2043. static int
  2044. RM_Rcv_FirmwareLoaded_Response(MODEM_STATE *pModemState)
  2045. {
  2046. int index;
  2047. char workstring[sizeof(FIRMWARE_READY_RESP) + 4];
  2048. char *to,*from;
  2049. from = FIRMWARE_READY_RESP;
  2050. to = workstring;
  2051. index = sizeof(FIRMWARE_READY_RESP) - 1;
  2052. while (index--)
  2053. *(to++) = *(from++);
  2054. from = ChecksumString;
  2055. index = 4;
  2056. while (index--)
  2057. *(to++) = *(from++);
  2058. *(to++) = 0;
  2059. index = 0;
  2060. index = READ_RESPONSE_STRING(
  2061. pModemState->portex,
  2062. workstring,
  2063. FIVE_SECONDS);
  2064. if (index) {
  2065. pModemState->status = RMODEM_FAILED;
  2066. Eprintf("Warning: Modem %s bad response to load",
  2067. pModemState->portex->SymbolicLinkName);
  2068. return(0);
  2069. }
  2070. pModemState->status = RMODEM_LOADED;
  2071. return(1);
  2072. }
  2073. /**********************************************************************
  2074. write a CSM byte. flush any '.' response...
  2075. **********************************************************************/
  2076. static int
  2077. RM_Snd_Loader_Data(MODEM_STATE *pModemState)
  2078. {
  2079. int loop;
  2080. loop = 100;
  2081. /*
  2082. see if there's any available space in the transmit FIFO. if not, pause...
  2083. */
  2084. while (
  2085. (!TxFIFOReady(pModemState->portex))
  2086. &&
  2087. (loop-- > 0)
  2088. ) {
  2089. /*
  2090. pause for any characters currently in the transmit FIFO to move on out...
  2091. */
  2092. ms_time_stall(1);
  2093. }
  2094. /*
  2095. if still no room, bail out...
  2096. */
  2097. if (!TxFIFOReady(pModemState->portex)) {
  2098. pModemState->status = RMODEM_FAILED;
  2099. Eprintf("Warning: Modem %s won't accept loader",
  2100. pModemState->portex->SymbolicLinkName);
  2101. return(0);
  2102. }
  2103. /*
  2104. write a byte, then go on to next modem...
  2105. */
  2106. ModemWrite(
  2107. pModemState->portex,
  2108. (char *)&Driver.ModemLoaderCodeImage[pModemState->index++],
  2109. (int)1);
  2110. /*
  2111. discard any data currently in the receive FIFO...
  2112. */
  2113. if (RxFIFOReady(pModemState->portex)) {
  2114. pModemState->status = RMODEM_FAILED;
  2115. Eprintf("Warning: Modem %s loader overrun",
  2116. pModemState->portex->SymbolicLinkName);
  2117. return(0);
  2118. }
  2119. return(1);
  2120. }
  2121. /**********************************************************************
  2122. write a firmware byte. flush any '.' response...
  2123. **********************************************************************/
  2124. static int
  2125. RM_Snd_Firmware_Data(MODEM_STATE *pModemState)
  2126. {
  2127. int origcount;
  2128. int loop;
  2129. origcount = (int)TxFIFOStatus(pModemState->portex);
  2130. loop = 100;
  2131. /*
  2132. see if there's any available space in the transmit FIFO. if not, pause...
  2133. */
  2134. while (
  2135. (!TxFIFOReady(pModemState->portex))
  2136. &&
  2137. (loop-- > 0)
  2138. ) {
  2139. /*
  2140. pause for characters currently in the transmit FIFO to make room...
  2141. */
  2142. ms_time_stall(1);
  2143. }
  2144. if (!TxFIFOReady(pModemState->portex)) {
  2145. pModemState->status = RMODEM_FAILED;
  2146. Eprintf("Warning: Modem %s won't accept firmware",
  2147. pModemState->portex->SymbolicLinkName);
  2148. return(0);
  2149. }
  2150. /*
  2151. write a byte, then go on to next modem...
  2152. */
  2153. ModemWrite(
  2154. pModemState->portex,
  2155. (char *)&Driver.ModemCodeImage[pModemState->index++],
  2156. (int)1);
  2157. /*
  2158. discard any data currently in the receive FIFO...
  2159. */
  2160. if (RxFIFOReady(pModemState->portex)) {
  2161. pModemState->status = RMODEM_FAILED;
  2162. Eprintf("Warning: Modem %s firmware overrun",
  2163. pModemState->portex->SymbolicLinkName);
  2164. return(0);
  2165. }
  2166. return(1);
  2167. }
  2168. /**********************************************************************
  2169. send modem load AT command...
  2170. **********************************************************************/
  2171. static int
  2172. RM_Snd_ModemLoad_Command(MODEM_STATE *pModemState)
  2173. {
  2174. SEND_CMD_STRING(pModemState->portex,MODEM_LOAD_CMD);
  2175. return(1);
  2176. }
  2177. /**********************************************************************
  2178. shutdown modem and port...
  2179. **********************************************************************/
  2180. static int
  2181. RM_CleanUp(MODEM_STATE *pModemState)
  2182. {
  2183. if (pModemState->status == RMODEM_FAILED) {
  2184. DownModem(pModemState);
  2185. return(0);
  2186. }
  2187. ModemUnReady(pModemState->portex);
  2188. return(1);
  2189. }
  2190. #endif
  2191. /**********************************************************************
  2192. load RocketModemII devices...
  2193. **********************************************************************/
  2194. void
  2195. InitRocketModemII(PSERIAL_DEVICE_EXTENSION ext)
  2196. {
  2197. #ifdef S_RK
  2198. DEVICE_CONFIG * cfg;
  2199. PSERIAL_DEVICE_EXTENSION portex,head_portex;
  2200. MODEM_STATE ModemState[8];
  2201. int modem_count,
  2202. loaded_modem_count,
  2203. modem_index,
  2204. retry;
  2205. ULONG index,version_index;
  2206. long checksum;
  2207. char VersionString[9];
  2208. char *cptr,*endptr;
  2209. // Eprintf("RocketModemII init start"); // turn on for timing purposes...
  2210. cfg = ext->config;
  2211. /*
  2212. verify this is a RMII board, 4 or 6 port, before proceeding further...
  2213. */
  2214. if (!cfg->ModemDevice) {
  2215. return;
  2216. }
  2217. if (
  2218. (cfg->PCI_DevID != PCI_DEVICE_RMODEM6)
  2219. &&
  2220. (cfg->PCI_DevID != PCI_DEVICE_RMODEM4)
  2221. )
  2222. return;
  2223. if (cfg->PCI_RevID != PCI_REVISION_RMODEM_II)
  2224. return;
  2225. /*
  2226. use the PDO port list, if present since they start up first under nt5.
  2227. prepare the ports to each modem...
  2228. */
  2229. head_portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2230. if (head_portex == (PSERIAL_DEVICE_EXTENSION)NULL) {
  2231. MyKdPrint(D_Init,("InitRocketModemII: No port extensions\r"))
  2232. return;
  2233. }
  2234. retry = 1;
  2235. do {
  2236. modem_count = 0;
  2237. head_portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2238. portex = head_portex;
  2239. while ((void *)portex) {
  2240. ModemIOReady(portex,115200);
  2241. ModemState[modem_count].status = RMODEM_NOT_LOADED;
  2242. ModemState[modem_count].portex = portex;
  2243. ModemState[modem_count].index = 0;
  2244. portex = portex->port_ext;
  2245. ++modem_count;
  2246. }
  2247. time_stall(ONE_SECOND);
  2248. /*
  2249. after pausing for ports to set up, start with modem hardware reset, before issuing ATI3,
  2250. making sure that modems are cleaned up and in command mode...
  2251. */
  2252. ModemResetAll(ext);
  2253. /*
  2254. enable RMII speaker...
  2255. */
  2256. ModemSpeakerEnable(head_portex);
  2257. /*
  2258. start with check on modem load status, by issuing ATI3 to just the first modem. if the first modem
  2259. isn't loaded, assume all the others aren't either. if the first modem is loaded, check the rest. if the
  2260. first modem receive fifo doesn't clear, mark accordingly, then proceed with loading...
  2261. */
  2262. (void) RM_Snd_ATI3_Command(ModemState);
  2263. ModemTxFIFOWait(ext);
  2264. (void) RM_Rcv_ATI3_Response(ModemState);
  2265. loaded_modem_count = 0;
  2266. if (ModemState[0].status == RMODEM_LOADED) {
  2267. /*
  2268. modem 0 was loaded. check remaining modems. if any aren't loaded, load them all...
  2269. */
  2270. ++loaded_modem_count;
  2271. modem_index = 1;
  2272. portex = head_portex->port_ext;
  2273. while ((void *)portex) {
  2274. if (ModemState[modem_index].status != RMODEM_FAILED)
  2275. (void) RM_Snd_ATI3_Command(&ModemState[modem_index]);
  2276. ++modem_index;
  2277. portex = portex->port_ext;
  2278. }
  2279. /*
  2280. ATI3 load probe command sent, waiting for OK or loaded firmware revision
  2281. response. if no modems respond, ignore for now...
  2282. */
  2283. ModemTxFIFOWait(ext);
  2284. modem_index = 1;
  2285. portex = head_portex->port_ext;
  2286. while ((void *)portex) {
  2287. if (ModemState[modem_index].status != RMODEM_FAILED)
  2288. (void) RM_Rcv_ATI3_Response(&ModemState[modem_index]);
  2289. ++modem_index;
  2290. portex = portex->port_ext;
  2291. }
  2292. /*
  2293. now see if any modems require loading. if any do, reset all modems again,
  2294. and then issue the download modem command to all modems...
  2295. */
  2296. modem_index = 0;
  2297. portex = head_portex->port_ext;
  2298. while ((void *)portex) {
  2299. if (ModemState[modem_index++].status == RMODEM_LOADED)
  2300. ++loaded_modem_count;
  2301. portex = portex->port_ext;
  2302. }
  2303. }
  2304. /*
  2305. if any modems are unloaded, load them all...
  2306. */
  2307. if (loaded_modem_count != modem_count) {
  2308. ModemResetAll(ext);
  2309. (void) IssueEvent(ext,RM_Snd_ModemLoad_Command,ModemState);
  2310. /*
  2311. load commands output. while they're leaving the transmit FIFO,
  2312. read in the CSM loader and modem firmware files...
  2313. */
  2314. if (LoadModemCode((char *)NULL,(char *)NULL)) {
  2315. Eprintf("Warning: Modem firmware file error");
  2316. FreeModemFiles();
  2317. continue;
  2318. }
  2319. /*
  2320. wait until the download commands are truly gone. then start waiting for
  2321. the response. if no modems respond, bail out...
  2322. */
  2323. ModemTxFIFOWait(ext);
  2324. if (IssueEvent(ext,RM_Rcv_ModemLoad_Response,ModemState) == 0) {
  2325. FreeModemFiles();
  2326. continue;
  2327. }
  2328. modem_index = 0;
  2329. while (modem_index < modem_count)
  2330. ModemState[modem_index++].index = 0;
  2331. /*
  2332. response received, apparently. grind through CSM loader file, sending a byte to
  2333. all modems...
  2334. */
  2335. index = 0;
  2336. while (index++ < Driver.ModemLoaderCodeSize)
  2337. (void) IssueEvent(ext,RM_Snd_Loader_Data,ModemState);
  2338. /*
  2339. spin while transmit FIFOs clear, then pause for responses to arrive...
  2340. */
  2341. ModemTxFIFOWait(ext);
  2342. /*
  2343. wait for loading at 115.2K response to CSM load. after response, pause
  2344. a moment for any remaining receive data to arrive. bail out if no modems
  2345. respond...
  2346. */
  2347. if (IssueEvent(ext,RM_Rcv_FirmwareLoader_Loaded,ModemState) == 0) {
  2348. MyKdPrint(D_Init,("InitRocketModemII: No recognized responses to loader load datastream\r"))
  2349. FreeModemFiles();
  2350. continue;
  2351. }
  2352. time_stall(HALF_SECOND);
  2353. modem_index = 0;
  2354. while (modem_index < modem_count)
  2355. ModemState[modem_index++].index = 0;
  2356. /*
  2357. grind through firmware file, sending a byte to all modems. skip the location
  2358. in the binary where the checksum will reside - it's just trash right now, but
  2359. space still has to be set aside for it - but don't include the trash in the
  2360. checksum (usually 0xFFFF)...
  2361. */
  2362. checksum = 0x00008000;
  2363. index = 0;
  2364. version_index = 0;
  2365. while (index < Driver.ModemCodeSize) {
  2366. (void) IssueEvent(ext,RM_Snd_Firmware_Data,ModemState);
  2367. if (
  2368. (index != (unsigned long)0xFFBE)
  2369. &&
  2370. (index != (unsigned long)0xFFBF)
  2371. )
  2372. checksum += Driver.ModemCodeImage[index];
  2373. /*
  2374. attempt to isolate the firmware version. version should be in form 'Vn.nnnan'. note
  2375. that we _could_ send another ati3 command to a representative modem to pick up the version
  2376. number after the load is complete, but that would take additional time...
  2377. also, note that though we've sent an ati3 command to at least one modem - so we have a
  2378. pretty good idea what the version is supposed to be based on the string we're expecting
  2379. on the response - we'll pretend that isn't applicable at this point to avoid dependencies
  2380. on the ati3 command...
  2381. whether that's a good idea or not remains to be seen. but the following processing seems
  2382. harmless at this time. if the form of the version changes, though, it might be annoying
  2383. to change the ati3 response string AND the following code to fit the new version form...
  2384. */
  2385. if (
  2386. (Driver.ModemCodeImage[index] == VERSION_CHAR)
  2387. &&
  2388. (!gModemToggle)
  2389. &&
  2390. (!version_index)
  2391. ) {
  2392. /*
  2393. only look for the version on the first modem board load, and if we haven't found the version yet,
  2394. see if the current character is a 'V'. if so, start the process of examining the following characters...
  2395. */
  2396. cptr = &Driver.ModemCodeImage[index];
  2397. endptr = Driver.ModemCodeImage + Driver.ModemCodeSize;
  2398. while (version_index < sizeof(VersionString)) {
  2399. /*
  2400. are we about to go past the end of the file? if so, bail out...
  2401. */
  2402. if (cptr >= endptr) {
  2403. version_index = 0;
  2404. break;
  2405. }
  2406. /*
  2407. check if this character looks ok...
  2408. */
  2409. if (
  2410. (*cptr < '.')
  2411. ||
  2412. (*cptr > 'Z')
  2413. ) {
  2414. /*
  2415. not a printable-enough character. have we enough characters to assume this is the version string? if not,
  2416. give up, start search over. if we do, though, then we're done, bail out...
  2417. */
  2418. if (version_index != (sizeof(VersionString) - 1))
  2419. version_index = 0;
  2420. break;
  2421. }
  2422. /*
  2423. printable character. if this is the third character in the string, though, it must be a dot. if not,
  2424. give up, start search over...
  2425. */
  2426. if (
  2427. ((*cptr == '.')
  2428. &&
  2429. (version_index != 2))
  2430. ||
  2431. ((*cptr != '.')
  2432. &&
  2433. (version_index == 2))
  2434. ) {
  2435. version_index = 0;
  2436. break;
  2437. }
  2438. /*
  2439. printable character, save it away for later. this includes the leading 'V', incidentally...
  2440. */
  2441. VersionString[version_index++] = *(cptr++);
  2442. VersionString[version_index] = 0;
  2443. }
  2444. }
  2445. index++;
  2446. }
  2447. ChecksumAscii((unsigned short *)&checksum);
  2448. /*
  2449. output one time messages. the version shouldn't change from modem board to modem board, and
  2450. neither should the computed checksum (though we do recompute it)...
  2451. */
  2452. if (!gModemToggle) {
  2453. if (version_index) {
  2454. Eprintf("RocketModemII firmware %s-%s",VersionString,ChecksumString);
  2455. }
  2456. else if (ChecksumString[0]) {
  2457. Eprintf("RocketModemII checksum %s",ChecksumString);
  2458. }
  2459. }
  2460. /*
  2461. all done with files, release them...
  2462. */
  2463. FreeModemFiles();
  2464. /*
  2465. spin while transmit FIFOs clear, then pause for response to arrive...
  2466. */
  2467. ModemTxFIFOWait(ext);
  2468. /*
  2469. wait for successful load message from each modem...
  2470. */
  2471. if (IssueEvent(ext,RM_Rcv_FirmwareLoaded_Response,ModemState) == 0) {
  2472. MyKdPrint(D_Init,("InitRocketModemII: No recognized responses to firmware load datastream\r"))
  2473. continue;
  2474. }
  2475. }
  2476. /*
  2477. pause for newly-loaded modems to settle down...
  2478. */
  2479. time_stall(HALF_SECOND);
  2480. /*
  2481. unready ports, reset ports associated with any failing modems. bail out if done...
  2482. */
  2483. if (IssueEvent(ext,RM_CleanUp,ModemState) == modem_count)
  2484. break;
  2485. } while (retry--);
  2486. ++gModemToggle;
  2487. // Eprintf("RocketModemII init end"); // turn on for timing purposes...
  2488. #endif
  2489. }
  2490. #ifdef S_RK
  2491. /**********************************************************************
  2492. check response...
  2493. **********************************************************************/
  2494. int
  2495. IssueEvent(PSERIAL_DEVICE_EXTENSION ext,int (*modemfunc)(),MODEM_STATE *pModemState)
  2496. {
  2497. PSERIAL_DEVICE_EXTENSION portex;
  2498. int responding_modem_count;
  2499. /*
  2500. issue event to each modem...
  2501. */
  2502. responding_modem_count = 0;
  2503. portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2504. while ((void *)portex) {
  2505. if (pModemState->status != RMODEM_FAILED) {
  2506. responding_modem_count += (modemfunc)(pModemState);
  2507. }
  2508. ++pModemState;
  2509. portex = portex->port_ext;
  2510. }
  2511. return(responding_modem_count);
  2512. }
  2513. /**********************************************************************
  2514. dynamic delay for transmit. waits only as long as necessary, but
  2515. doesn't get caught if a transmit fifo stalls (for whatever reason)...
  2516. **********************************************************************/
  2517. void
  2518. ModemTxFIFOWait(PSERIAL_DEVICE_EXTENSION ext)
  2519. {
  2520. PSERIAL_DEVICE_EXTENSION portex;
  2521. int index,activity;
  2522. int fifo_count[16]; // arbitrary, but reasonably safe, array size
  2523. int fifo_stall[16]; // ditto
  2524. /*
  2525. build baseline transmit fifo counts, init stall counts to zero...
  2526. */
  2527. portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2528. index = 0;
  2529. while ((void *)portex) {
  2530. fifo_count[index] = (int)TxFIFOStatus(portex);
  2531. fifo_stall[index] = 0;
  2532. ++index;
  2533. portex = portex->port_ext;
  2534. }
  2535. /*
  2536. loop until all transmit fifos are empty, or we've given up on the stalled ones...
  2537. */
  2538. do {
  2539. index = 0;
  2540. activity = 0;
  2541. portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2542. while ((void *)portex) {
  2543. /*
  2544. check only those ports that indicate data in the transmit fifo, but then only as
  2545. long as they don't appear to be stalled...
  2546. */
  2547. if (
  2548. ((int)TxFIFOStatus(portex))
  2549. &&
  2550. (fifo_stall[index] < MAX_STALL)
  2551. ) {
  2552. if (fifo_count[index] == (int)TxFIFOStatus(portex)) {
  2553. /*
  2554. pause for a non-moving transmit fifo, flag this fifo as suspect...
  2555. */
  2556. fifo_stall[index]++;
  2557. ms_time_stall(1);
  2558. }
  2559. else {
  2560. /*
  2561. this particular transmit fifo count changed. pick up new value to monitor. unflag this
  2562. fifo as suspect...
  2563. */
  2564. fifo_count[index] = (int)TxFIFOStatus(portex);
  2565. fifo_stall[index] = 0;
  2566. }
  2567. /*
  2568. whether they're stalled or not, flag fifos as still active. this goes on until
  2569. they're empty, or stall limit count is reached...
  2570. */
  2571. ++activity;
  2572. }
  2573. portex = portex->port_ext;
  2574. ++index;
  2575. }
  2576. /*
  2577. still some (apparent) activity in transmit fifos? yep, loop some more...
  2578. */
  2579. } while (activity);
  2580. }
  2581. /**********************************************************************
  2582. unready and reset modem...
  2583. **********************************************************************/
  2584. void
  2585. DownModem(MODEM_STATE *pModemState)
  2586. {
  2587. ModemUnReady(pModemState->portex);
  2588. ModemReset(pModemState->portex,1);
  2589. time_stall(Driver.MdmSettleTime);
  2590. ModemReset(pModemState->portex,0);
  2591. }
  2592. /**********************************************************************
  2593. reset all modems on this board at the same time...
  2594. **********************************************************************/
  2595. void
  2596. ModemResetAll(PSERIAL_DEVICE_EXTENSION ext)
  2597. {
  2598. PSERIAL_DEVICE_EXTENSION portex;
  2599. portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2600. while ((void *)portex) {
  2601. ModemReset(portex,1);
  2602. portex = portex->port_ext;
  2603. }
  2604. time_stall(HALF_SECOND);
  2605. portex = (ext->port_pdo_ext) ? ext->port_pdo_ext : ext->port_ext;
  2606. while ((void *)portex) {
  2607. ModemReset(portex,0);
  2608. portex = portex->port_ext;
  2609. }
  2610. time_stall(ONE_SECOND);
  2611. }
  2612. /**********************************************************************
  2613. 2 byte conversion to ascii...
  2614. **********************************************************************/
  2615. void
  2616. ChecksumAscii(unsigned short *valueptr)
  2617. {
  2618. int count,index;
  2619. unsigned short work;
  2620. ChecksumString[4] = 0;
  2621. index = 0;
  2622. count = 3;
  2623. do {
  2624. work = (*valueptr) & 0x7fff;
  2625. work >>= (count * 4);
  2626. work &= 0x000F;
  2627. if (work > 9)
  2628. work += '7';
  2629. else
  2630. work += '0';
  2631. ChecksumString[index++] = (unsigned char)work;
  2632. } while (count--);
  2633. }
  2634. #endif
  2635. /*********************************************************************************
  2636. *
  2637. * get_comdb_offsets
  2638. *
  2639. *********************************************************************************/
  2640. static int get_comdb_offsets( IN char *portLabel, OUT int *indx, OUT BYTE *mask )
  2641. {
  2642. char *pComLbl;
  2643. int i, portNum, portIndx;
  2644. BYTE portMask;
  2645. // Make sure a COMxx string is being passed in
  2646. ASSERT( portLabel );
  2647. ASSERT( indx );
  2648. ASSERT( mask );
  2649. if ( strlen( portLabel ) < 4 ) {
  2650. return 0;
  2651. }
  2652. if ( strncmp( portLabel, "COM", 3 ) ) {
  2653. return 0;
  2654. }
  2655. // A lot of checking, but if the wrong ComDB bit is cleared, the
  2656. // corresponding COM# may get reassigned although another device
  2657. // is using it.
  2658. pComLbl = portLabel + 3;
  2659. for ( i = 0; pComLbl[i]; i++ ) {
  2660. if (!our_isdigit( pComLbl[i] )) {
  2661. return 0;
  2662. }
  2663. }
  2664. // Convert the string to numeric, then translate into bit & byte
  2665. // offsets
  2666. portNum = getint( pComLbl, NULL );
  2667. portMask = (BYTE) (1 << ( (portNum - 1) % 8 ));
  2668. portIndx = (int) ((portNum - 1) >> 3);
  2669. MyKdPrint( D_Init, ("Mask value for COM%d is 0x%02x at byte index %d\n",
  2670. portNum, portMask, portIndx ) );
  2671. *indx = portIndx;
  2672. *mask = portMask;
  2673. return portNum;
  2674. }
  2675. /*********************************************************************************
  2676. *
  2677. * get_com_db
  2678. *
  2679. * Makes sure the bit in the \Registry\Machine\System\CurrentControlSet\Control\COM Name Arbiter
  2680. * for the specific port gets cleared on an uninstall. Ordinarily the PnP Manager
  2681. * does this automatically but old builds of W2000 don't nor do more recent builds
  2682. * under certain circumstances. If this bit isn't cleared the OS won't reuse the
  2683. * COM port number if the RocketPort is re-installed or another serial device is
  2684. * installed.
  2685. *
  2686. *********************************************************************************/
  2687. static char *szRMSCCComNameArbiter =
  2688. { "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\COM Name Arbiter" };
  2689. static char *szValueID = { "ComDB" };
  2690. int clear_com_db( char *szComport )
  2691. {
  2692. HANDLE key_handle = NULL;
  2693. // BYTE *buffer;
  2694. BYTE *data_ptr = NULL;
  2695. int i, stat, indx, port_num;
  2696. BYTE portMask;
  2697. USTR_40 ubuf; // Unicode key name
  2698. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  2699. ULONG length;
  2700. // Get the COM #
  2701. indx = 0;
  2702. portMask = 0;
  2703. if ( szComport != NULL ) {
  2704. port_num = get_comdb_offsets( szComport, &indx, &portMask );
  2705. if ( port_num < 3 || port_num > 256 ) {
  2706. MyKdPrint( D_Error, ("Invalid COM port number from %d\n", szComport) );
  2707. return 1;
  2708. }
  2709. }
  2710. else {
  2711. MyKdPrint( D_Error, ("COM port parameter was NULL\n") );
  2712. return 1;
  2713. }
  2714. // Open the registry key
  2715. stat = our_open_key( &key_handle,
  2716. NULL,
  2717. szRMSCCComNameArbiter,
  2718. KEY_ALL_ACCESS );
  2719. if ( stat ) {
  2720. MyKdPrint(D_Error, ("Unable to find Com Port Arbiter key\n"));
  2721. return 1;
  2722. }
  2723. // convert our name to unicode
  2724. CToUStr((PUNICODE_STRING) &ubuf, // where unicode struct & string gets put
  2725. szValueID, // our c-string we wish to convert
  2726. sizeof(ubuf));
  2727. // The 2-pass ZwQueryValueKey approach ensures accurate buffer size allocation.
  2728. // Pass 1 with a NULL buffer parameter returns the length of the
  2729. // PKEY_VALUE_PARTIAL_INFORMATION structure. After allocating a buffer of
  2730. // this length, pass 2 reads the structure. The trick is to ignore any return
  2731. // code on pass 1 except STATUS_OBJECT_NAME_NOT_FOUND, i.e., the value doesn't
  2732. // exist.
  2733. // Determine the required size for the registry data buffer
  2734. stat = ZwQueryValueKey( key_handle,
  2735. (PUNICODE_STRING) &ubuf,
  2736. KeyValuePartialInformation,
  2737. NULL,
  2738. 0,
  2739. &length);
  2740. if ( stat == STATUS_OBJECT_NAME_NOT_FOUND || length == 0L ) {
  2741. MyKdPrint(D_Error, ("Unable to find %s in specified key\n", szValueID));
  2742. ZwClose( key_handle );
  2743. return 1;
  2744. }
  2745. MyKdPrint(D_Init,
  2746. ("Allocating PKEY_VALUE_PARTIAL_INFORMATION buffer: %d bytes\n", length));
  2747. // Make a buffer for the KEY_VALUE_PARTIAL_INFORMATION struct
  2748. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool( PagedPool, length );
  2749. if ( KeyValueInfo == NULL ) {
  2750. MyKdPrint(D_Error, ("Unable to allocate PKEY_VALUE_PARTIAL_INFORMATION struct\n"))
  2751. ZwClose( key_handle );
  2752. return 1;
  2753. }
  2754. RtlZeroMemory( KeyValueInfo, length );
  2755. // Now get the actual data structure
  2756. stat = ZwQueryValueKey( key_handle,
  2757. (PUNICODE_STRING) &ubuf,
  2758. KeyValuePartialInformation,
  2759. KeyValueInfo,
  2760. length,
  2761. &length );
  2762. if ( !NT_SUCCESS(stat) || length == 0L ) {
  2763. MyKdPrint(D_Error, ("Unable to read PKEY_VALUE_PARTIAL_INFORMATION struct\n"));
  2764. ExFreePool( KeyValueInfo );
  2765. ZwClose( key_handle );
  2766. return 1;
  2767. }
  2768. length = KeyValueInfo->DataLength;
  2769. MyKdPrint(D_Init, ("Data buffer length is %d bytes\n", length));
  2770. if ( KeyValueInfo->Type != REG_BINARY ) {
  2771. MyKdPrint(D_Error, ("Unexpected registry type in PKEY_VALUE_PARTIAL_INFORMATION struct\n"));
  2772. ExFreePool( KeyValueInfo );
  2773. ZwClose( key_handle );
  2774. return 1;
  2775. }
  2776. data_ptr = (PCHAR)(&KeyValueInfo->Data[0]);
  2777. if ( data_ptr ) {
  2778. MyKdPrint(D_Init, ("ComDB byte %d is 0x%02x\n", indx, data_ptr[indx]));
  2779. if ( (data_ptr[indx] & portMask) != 0 ) {
  2780. MyKdPrint(D_Init,
  2781. ("Clearing bit position 0x%02x in ComDB byte value 0x%02x\n",
  2782. portMask, data_ptr[indx]));
  2783. data_ptr[indx] &= ~portMask;
  2784. // Now we write the modified data back to the registry
  2785. stat = our_set_value( key_handle,
  2786. (char *)szValueID,
  2787. data_ptr,
  2788. length,
  2789. REG_BINARY);
  2790. if ( stat ) {
  2791. MyKdPrint(D_Error, ("Unable to write ComDB value\n"));
  2792. ExFreePool( KeyValueInfo );
  2793. ZwClose( key_handle );
  2794. return 1;
  2795. }
  2796. }
  2797. else {
  2798. // Previously cleared
  2799. MyKdPrint(D_Init,
  2800. ("Bit position 0x%02x already cleared in ComDB byte value 0x%02x!\n",
  2801. portMask, data_ptr[indx]));
  2802. }
  2803. }
  2804. // cleanup
  2805. ExFreePool( KeyValueInfo );
  2806. ZwClose( key_handle );
  2807. return 0;
  2808. }